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

拈花ヽ惹草 提交于 2019-12-09 19:12:16

问题


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.


回答1:


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];



回答2:


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);



回答3:


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




回答4:


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



来源:https://stackoverflow.com/questions/4909972/how-do-i-call-methods-in-a-class-that-i-created-dynamically-with-nsclassfromstri

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!