编辑:是的,我做错了。很可能通过在类级别上使用协议来了解init方法。这是我很少做的事情,所以我一开始并没有想到这一点(请参阅有关我使用协议对其回答的链接问题)。是的,这个问题被打破了。正如bbum所说,绝对没有理由这样做。
[1]中我的问题的背景。
出于设计原因(数据映射器模式)我需要初始化我知道的类是某个基类(ManagedEntity)的子类。我断言这一次 - 然后我想创建尽可能多的实例,并尽可能快(我正在为iOS编程)。但是,由于我需要在其中创建具体实例的类不知道任何模型类,因此存储并用于创建实体实例的元类只是已知类型为Class。
长话短说:我不能简单地使用[[[_EntityClass] alloc] initWithBlah:something],因为EntityClass是未知的,只是在那里被称为类型类,因此init方法initWithBlah当然是未知的 - 但我知道它必须存在(它必须是设计的基类的子类,它在初始化映射器时被声明一次)。
因此,为了使用我知道存在的init方法创建未知类的实例,我需要构造一个方法调用。这应该在未知类上调用initWith:something选择器并创建它的实例。
我认为我应该使用objc_msgSend而不是NSInvocation,因为后者应该慢一个数量级[2]。 init方法应该不会改变,并且需要一个参数。
那么......相当于:
ManagedEntity *newEntity = [[ManagedEntity] alloc] initWithEntityDescription:_entityDescription];
使用objc_msgSend?
[1] Create a subclass of a class using parent's init - from another class
[2] http://www.mikeash.com/pyblog/performance-comparisons-of-common-operations-leopard-edition.html
答案 0 :(得分:2)
更好:
Class klass = NSClassFromString(className);
id newEntity = [[klass alloc] initWithEntity:entity insertIntoManagedObjectContext:ctx];
当您拥有固定选择器时,没有理由直接使用objc_msgSend()
。您始终可以使用普通语法直接调用选择器。最糟糕的情况是,您可能需要输入其中一个调用的返回值。
唯一的要求是编译器在编译上述调用站点之前的某个时间看到了initWithEntity:insertIntoManagedObjectContext:
的声明。
示例:
@interface NSObject(BobsYourUncle)
- (void)bob:sender;
@end
...
Class klass = NSClassFromString(@"NSManagedObject");
[[klass alloc] bob:nil];
以上编译就好了。并非我建议挂起NSObject
的随机定义。相反,#import
抽象超类的声明(应该包含选择器声明)。
答案 1 :(得分:1)
id cls = NSClassFromString(className);
id alloced_cls = objc_msgSend(cls, @selector(alloc));
id newEntity = objc_msgSend(alloced_cls, @selector(initWithEntity:insertIntoManagedObjectContext:), entity, ctx);
return newEntity;