-3

编辑:是的,我做错了。很可能通过使用类级别的协议来了解 init 方法。这是我很少做的事情,所以一开始我并没有想到(请参阅有关我使用协议对它的回答的链接问题)。所以是的,这个问题被打破了。正如bbum所说,绝对没有理由这样做。

我在 [1] 中的问题的背景。

出于设计原因(数据映射器模式),我需要初始化我知道是某个基类(ManagedEntity)的子类的类。我为此断言一次 - 然后我想创建尽可能多的实例,并且尽可能快(我正在为 iOS 编程)。但是,由于我需要在其中创建具体实例的类不知道任何模型类,因此存储并用于创建实体实例的元类只知道是 Class 类型。

长话短说:我不能简单地使用 [[[_EntityClass] alloc] initWithBlah:something],因为 EntityClass 是未知的,只是在那里被称为类型 Class,因此 init 方法 initWithBlah 当然是未知的 - 但我知道它必须存在(它必须是设计基类的子类,在初始化映射器时断言一次)。

因此,为了使用我知道存在的 init 方法创建未知类的实例,我需要构造一个方法调用。这应该调用未知类的 initWith:something 选择器并创建它的实例。

我认为我应该使用 objc_msgSend 而不是 NSInvocation,因为后者应该慢一个数量级 [2]。init 方法应该不会改变,并且需要一个参数。

所以......什么相当于:

ManagedEntity *newEntity = [[ManagedEntity] alloc] initWithEntityDescription:_entityDescription]; 

用 objc_msg 发送?

[1]使用父类的 init 创建一个类的子类 - 来自另一个类

[2] http://www.mikeash.com/pyblog/performance-comparisons-of-common-operations-leopard-edition.html

4

2 回答 2

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抽象超类的声明(应该包含选择器声明)。

于 2013-10-20T18:06:33.157 回答
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;
于 2013-10-20T16:23:36.303 回答