开发者

How do I call methods in a class that I created dynamically with NSClassFromString?

开发者 https://www.devze.com 2023-02-09 06:46 出处:网络
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\

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:.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号