iOS - Objective-C - Fast Reflection for Value Types

Stephen Zaharuk / Monday, January 11, 2016

A long while back, i wrote an article on Reflection. 

C# to Objective-C - Part 6 : Reflection

And the code in that article still holds true. As you know, reflection is really expensive but sometimes a necessary evil. However, its especially expensive for value types because of boxing and unboxing. 

I wrote another article on this topic a while ago as well. 

Going From C# To Objective-C: Boxing and Unboxing

Basically, whenever you use reflection, Obj-c takes the value and wraps it in an NSValue object or an NSNumber if you're dealing with number. 

Today, i'm going to show you, how you can actually skip the boxing and unboxing. Although its a bit tricky, it'll definitely speed up your application if you're using reflection to loop through large amounts of data. 

To keep the topic as simple as possible, i'm going to show you how to do this for double's. However, you can customize this to support any other value type, although you'll have to know what value types you're supporting up front. 

First we need to typedef a method called "getDouble" that will return our value:

typedef double (*getDouble)(id, SEL);

Next we need to define a block called "helperBlock" that we will invoke for reflection:

typedef double (^helperBlock)(NSObject*, SEL, IMP);

Now we can create an instance of helperBlock

helperBlock block = ^double (NSObject* obj, SEL selector, IMP method)
{
getDouble f = (getDouble)method;
return f(obj, selector);
};

Notice how we're casing the IMP as a our getDouble method, so that we know what the return type is. 

Lets create a dummy class that we'd use this against:

@interface ObjectToReflect

@property(nonatomic, assign)double value;
@property(nonatomic, assign)NSString* key;

@end

So how would we reflect and get the value property? Well, lets assume we created an array of "ObjectToReflect" objects. 

IMP method = nil;

for(NSObject* obj in data)
{
    if(method == nil)
       method = [obj methodForSelector:getProp];
   

    double val = block(obj, NSSelectorFromString(@“value”), method);
}

And now you've reflected against your data object. Like I said, its a bit complicated, but hopefully this helps simplify things. And it certainly will make your code much faster. 

Hope this helps!

By Stephen Zaharuk (SteveZ)