atomikpanda
atomikpanda

Reputation: 1886

Varying Return Type Objective-C or c

How can I have a method/function that can return any type? For example sometimes the type will need to be float and sometimes it will need to be NSString* so id won't work because float isn't an id. I am not opposed to doing it in a c or c++ function if it's easier.

The reason why I need a dynamic return type is because I'm using objc/runtime to get an Ivar.

I would like some_type to be able to anything:

- (some_type)getIvarWithName:(const char *)name in:(id)obj
{
Ivar ivar(class_getInstanceVariable(object_getClass(obj),name));
return (some_type)ivar;
}

Upvotes: 0

Views: 254

Answers (5)

atomikpanda
atomikpanda

Reputation: 1886

I found that using a template in c++ works to have a custom type The following code works best for my situation:

template <typename _type>
static inline _type & hookVar(id self, NSString*name)
{
    Ivar ivar(class_getInstanceVariable(object_getClass(self),[name UTF8String]));
    #if __has_feature(objc_arc)
    void *pointer(ivar == NULL ? NULL : reinterpret_cast<char *>((__bridge void *)self) + ivar_getOffset(ivar));
    #else
    void *pointer(ivar == NULL ? NULL : reinterpret_cast<char *>(self) + ivar_getOffset(ivar));
    #endif
    return *reinterpret_cast<_type *>(pointer);
}

To call the function I just use something like:

NSWindow *win = hookVar<NSWindow*>(self, @"_window");

Upvotes: 0

Cy-4AH
Cy-4AH

Reputation: 4586

Ofcourse it's weird solution, but you have weird question.

You need enable objective-c++: rename .m-file to .mm Then yours code will look something like that:

void weird_function(int a)
{
   switch (a)
   {
       case 0: throw @"Hello";
       default: throw a;
   }
}

void some_code(int a)
{
    try
    {
        weird_function(a);
    }
    catch (int a)
    {
         NSLog(@"Catch int: %d", a);
    }
    catch (NSString* str)
    {
         NSLog(@"Catch string: %@", str);
    }
}

Yours method can be implemented something like that:

union ValueHolder
{
    void* voidPtrValue;
    int intValue;
    float floatValue;
    NSString* nssstringValue;
};

- (void)getIvarWithName:(const char *)name in:(id)obj
{
    ValueHolder vh;
    Ivar ivar = object_getInstanceVariable(obj,name, &vh.voidPtrValue));
    if (NULL == ivar)
        return;
    const char* encoding = ivar_getTypeEncoding(ivar);
    if (0 == strcmp(encoding, @encode(int)))
        throw vh.intValue;
    if (0 == strcmp(encoding, @encode(float)))
        throw vh.floatValue;
    if (0 == strcmp(encoding, "@\"NSString\""))
        throw vh.nsstringValue;
}

Upvotes: 0

user2105505
user2105505

Reputation: 706

The first thing to think about is why you would need a function that can return any type. It really doesn't make sense because you wouldn't be able to assign the value to anything, since you don't know the type. Of course, the situation is different when dealing strictly with Obj-C objects, as the language utilizes unknown objects with the id keyword. Unknown objects are like mixing Honeycrisp apples with Macintosh apples (no pun intended), and what you are trying to do is like mixing Honeycrisp apples with airplanes! However, if you want a certain type returned based off of the parameters (such as returning int for int parameters and float for float parameters), then you can overload the functions. Otherwise, then only way that I know of to return absolutely anything would be a void pointer (void *). This would point to a chunk of data that could really be anything. But back to the original problem. What does it represent and how long is it? Good luck!

UPDATE: As other answers mention, you can wrap simple data types (int, float, etc.) in objects such as NSNumbers or NSValues, which will work for your case. But when extending to more general scenarios with complex types such as structs, these generally can't be wrapped in built-in classes. You would need to make your own class using Obj-C.

Upvotes: 1

Hermann Klecker
Hermann Klecker

Reputation: 14068

There is no polymorphism of that kind in Obj-C. If you know in advance what will be returned then you could use to methods of course. Retruning id would work when you use an NSNumber for the float value. You could even introduce a response object that either carries a number or a string and provides (bool) isNumber and (bool) isString methods for later processing.

But what are you really up to? In which context are you using that and what do you really try to achieve. To me it sounds as if there may be better solutions available.

Upvotes: 0

Rich
Rich

Reputation: 8202

Return a float wrapped in an NSNumber, then you can use the id return type.

To simplify it, you can even use boxing literals, for example:

return @(1.1f);

Upvotes: 3

Related Questions