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

时间:2013-10-20 15:03:44

标签: objective-c

编辑:是的,我做错了。很可能通过在类级别上使用协议来了解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

2 个答案:

答案 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;