Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dont understand how NSClassFromString can be used for conditional calling

Tags:

ios

I have a testing class within my project that is there during the development phase but will be compiled out for the app store build.

I've read in several books that NSClassFromString can be used to determine if a class exists with example code such as:

if (NSClassFromString(@"SomeClass") != nil)
{
[SomeClass someMethod];
}
else
{
code not using SomeClass
}

However after putting this into practice in my project, I find that I'm getting a linking error for the target where I have removed the source file containing SomeClass.

Therefore my conclusion is this mechanism for determining the presence/absence of a class is only useful if that class is within a library or source file where you are using other classes ( a detail which is missing from the books that mention this technique). Or am I missing something?

like image 947
Gruntcakes Avatar asked Dec 10 '12 23:12

Gruntcakes


1 Answers

NSClassFromString searches the runtime for the named class. Ipso facto it will determine if the class exists.

For the compiler successfully to get past static references like [SomeClass someMethod] it needs something to link against.

You're right that the mechanism therefore works when you link to something like Foundation and Apple adds an extra class there, like checking whether NSJSONSerialization exists.

It also works if you weak link against a framework that may or may not be present. So e.g. you could weak link against Twitter.framework and use [TWRequest alloc] .... You'd still be able to build and deploy on iOS 4 where there wasn't a Twitter framework at all.

Apple have actually slightly modified the way that libraries are stored and are transitioning to allowing if([TWRequest class]) or whatever to be used in place of the explicit NSClassFromString where you weak link.

However in your case it sounds like you want to either link to a static library or not link to it? So the class may or may not be available at runtime but also may or may not be visible to the linker?

In that case you just need to avoid literal references to the metaclass. So you could do something like:

Class someClassMetaClass = NSClassFromString(@"SomeClass");

if(someClassMetaClass)
{
    SomeClass *instance = [[someClassMetaClass alloc] init];
    /* ... */
}

As long as the header file is visible the compiler will be happy allowing you to specify the SomeClass type for pointers (because that doesn't go into the binary anyway) and will be able to suggest the usual autocompletions and warnings against the published interface. Just make sure you always address the metaclass through a pointer to the Class that you got from the runtime rather than directly. That way there's nothing that the linker needs to follow up on.

like image 171
Tommy Avatar answered Nov 15 '22 09:11

Tommy