使用 objc_msgSend 初始化一个带有一个参数的类



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

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

出于设计原因(数据映射器模式),我需要初始化我知道是某个基类(托管实体)的子类的类。我为此断言一次 - 然后我想创建尽可能多的实例,并且尽可能快(我正在为 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] 使用父类的 init 创建类的子类 - 从另一个类

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

更好:

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

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;

相关内容

最新更新