I'm interested in replicating the sort of functionality that you see with Apple frameworks: where Apps can take advantage of new frameworks on more recent versions of iOS but don't fail when they're missing.
Of course if there's another approach to solving the problem I'd love to see it.
The position I'm in is as follows:
Company-A provides an iOS framework (hereafter named FrameA) to third parties that they can link into their Apps.
I am tasked with creating an optional module that can be "bolted on" to FrameA, but isn't actually a part of it (this is due to FrameA often being updated and customized for different customers and other business limitations).
The third parties can choose to use the bolt-on library (or framework, or whatever will work) or not. If it is present FrameA must link it and the code execute it's functionality. If it is not present then FrameA continues as it does now. It must work for third parties that receive new versions of FrameA but not the bolt-on library. I should make as few changes to FrameA as possible since those changes will have to be maintained going forwards by another team.
I also need to do this within Apples submission rules, the solution must support at least iOS6, 7 and 8. So Dynamic linking is not allowed. Company-A provides FrameA directly to the third-parties, so the only part that Apple has to approve is the final App.
I've done this kind of thing on a small scale, and it's not too bad.
From within FrameA, use a factory to instantiate all bolt-on objects. The factory uses NSClassFromString()
to dynamically fetch the class. Avoid class methods: this makes things harder. Whenever possible, use protocols instead of classes: this makes things easier.
- (id<FABoltOnProtocol>)createBoltOnClass
{
return [[NSClassFromString(@"BOBoltOnClass") alloc] init];
}
This code will run even if BOBoltOnClass
is not linked into the final app. NSClassFromString(@"BOBoltOnClass")
will return Nil
, [Nil alloc]
returns nil
, and [nil init]
returns nil
.
You can test for bolt-on's existence the same way.
BOOL MyHasBoltOn
{
return NSClassFromString(@"BOBoltOnClass") != Nil;
}
The drawback is FrameA must be compiled with the headers from bolt-on. This is why I recommended protocols. These protocols can be owned by FrameA and bolt-on will conform to it (NOTE: I hinted at this by naming the protocol with FrameA's prefix FA and the class with bolt-on's prefix BO).
Finally, being a string, you can read @"BOBoltOnClass" from a config file so you can swap different bolt-ons as needed.
Be aware that the build flag -ObjC must be set, as otherwise the compiler will not load symbols for the bolt-on classes as they're not called conventionally.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments