How do I call methods in a class that I created dynamically with NSClassFromString?
The reason I am doing dynamic class loading is because I am creating a single set of files that can be used across multiple similar projects, so doing a #import and then normal instantiation just won't work. Dynamic classes allows me to do this开发者_高级运维, as long as I can call methods within those classes. Each project has this in the pch with a different "kMediaClassName" name so I can dynamically load different classes based on the project I'm in:
#define kMediaClassName @"Movie"
Here is the code I am using to get an instance of a class dynamically:
Class mediaClass = NSClassFromString(kMediaClassName);
id mediaObject = [[[mediaClass alloc] init] autorelease];
Then I try to call a method within that dynamic class:
[mediaObject doSomething];
When I then type this into Xcode, the compiler shows a warning that the class doesn't have this method, even though it does. I can see it right there in my Movie.h file. What is going on? How do I call a method from a dynamically instantiated class?
And what if I need to pass multiple arguments?
[mediaObject loadMedia:oneObject moveThe:YES moveA:NO];
Thanks for the help in advance.
you can declare a protocol, like so:
@protocol MONMediaProtocol
/*
remember: when synthesizing the class, you may want
to add the protocol to the synthesized class for your sanity
*/
- (BOOL)downloadMediaAtURL:(NSURL *)url toPath:(NSString *)path loadIfSuccessful:(BOOL)loadIfSuccessful;
/* ...the interface continues... */
@end
in use:
Class mediaClass = NSClassFromString(kMediaClassName);
assert(mediaClass);
id<MONMediaProtocol> mediaObject = [[[mediaClass alloc] init] autorelease];
assert(mediaObject);
NSURL * url = /* expr */;
NSString * path = /* expr */;
BOOL loadIfSuccessful = YES;
BOOL success = [mediaObject downloadMediaAtURL:url toPath:path loadIfSuccessful:loadIfSuccessful];
Well it might be there, but the Compiler doesn't know about it because it assumes that mediaClass is just some Class object, but nothing specific. NSClassFromString() is a runtime function and thus can't give the compiler a hint at compile time about the object.
What you can do:
- Ignore the warning
- Use
[media performSelector:@selector(doSomething)];
And btw, this is wrong:
Class mediaClass; = NSClassFromString(kMediaClassName);
it should be:
Class mediaClass = NSClassFromString(kMediaClassName);
An easier and fancier solution than NSInvocation :)
Class mediaClass = NSClassFromString(kMediaClassName);
if(mediaClass){
id mediaObject = class_createInstance(mediaClass,0);
objc_msgSend(mediaObject, @selector(doSomethingWith:andWith:alsoWith:), firstP, secondP,thirdP);
}
Explanation:
class_createInstance(mediaClass,0);
does exactly the same as [[mediaClass alloc] init];
if you need to autorelease it, just do the usual [mediaObject autorelease];
objc_msgSend()
does exactly the same as performSelector:
method but objc_msgSend()
allows you to put as many parameters as you want. So, easier than NSInvocation
right? BTW, their signature are:
id class_createInstance(Class cls, size_t extraBytes)
id objc_msgSend(id theReceiver, SEL theSelector, ...)
For more info you can refer the Objective-C Runtime Reference
As Joe Blow says, NSInvocation will help you here, though NSObject has a couple of shortcut methods that you can use: -performSelector:
, -performSelector:withObject:
, and -performSelector:withObject:withObject:
.
精彩评论