Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 使用objc_msgSend初始化具有一个参数的类_Objective C - Fatal编程技术网

Objective c 使用objc_msgSend初始化具有一个参数的类

Objective c 使用objc_msgSend初始化具有一个参数的类,objective-c,Objective C,编辑:是的,我做错了。通过在类级别使用协议,很可能知道init方法。这是我很少做的事情,所以一开始我并没有想到这一点(请参阅关于我使用协议回答的链接问题)。是的,这个问题被打破了。正如bbum所说,绝对没有理由这样做。 [1]中我问题的背景 出于设计原因(数据映射器模式),我需要初始化我知道是某个基类(ManagedEntity)的子类的类。我为这个断言一次,然后稍后我想创建尽可能多的实例,并且尽可能快(我正在为iOS编程)。然而,由于我需要在其中创建具体实例的类不知道任何模型类,所以存储并用于

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

[1]中我问题的背景

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

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

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

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

所以。。。这相当于:

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

[1]

[2] 更好:

Class klass = NSClassFromString(className);
id newEntity = [[klass alloc] initWithEntity:entity insertIntoManagedObjectContext:ctx];
当您有固定的选择器时,没有理由直接使用
objc\u msgSend()
。您始终可以使用常规语法直接调用选择器。最糟糕的情况是,您可能必须键入其中一个调用的返回值

唯一的要求是编译器在编译上述调用站点之前的某个时间看到了
initWithEntity:insertIntoManagedObjectContext:
的声明

例如:

@interface NSObject(BobsYourUncle)
- (void)bob:sender;
@end

...

    Class klass = NSClassFromString(@"NSManagedObject");
    [[klass alloc] bob:nil];

上面的编译很好。我并不建议挂起
NSObject
的随机定义。相反,
#导入
抽象超类的声明(其中应该包含选择器声明)。

为什么我会在这个问题上遭到否决?请说明您理解我试图做的事情,并说明原因……我不明白,但直接将objc_msgSend用于alloc/init类是错误的。它反对OOP和封装,最糟糕的是它严重依赖于内部->你应该重新审视这个问题。[1]似乎是个傻瓜,解释见[1]。我做了研究,这是一个极端的例子。设计的地图绘制者不知道具体的模型。与NSManagedObject类似,模型是ManagedEntity的一个子类,我必须在映射器中使用参数创建它。它与我前面的问题不同。我之前的questin询问了一种了解该方法的方法,因为我知道它是一个已知类的子类。我特别想避免使用NSInvocation,或objc_msgSend——正如问题中所述。这是不可能的,因此这个新问题,问的正是前一个问题不涉及的内容。我现在认为我做错了,在类级默认方法初始化上使用协议是完全可能的。谢谢你的回答,这就是我所要求的。你可以这样做,但没有意义。只要直接调用这些方法,如果必须的话,可以使用cast。请注意,
cls
应该是
Class
类型,而不是
id
。我知道并说过N次:)但这是他在新的XCode 5(iOS,其他可能也)项目中默认明确想要的。未知方法被视为错误(在我看来是有充分理由的)。所以它不会编译,除非更改设置。诚然,正如我所说,我做错了——我现在只是在映射器中存储一个“类”iVar,该协议知道initWith:@benjist,但这不是一个未知的方法;只要您在调用站点之前导入,那么在启用所有与选择器相关的警告的情况下,它就可以正常编译。现在我明白您的意思了。但正如您所说,NSObject上的类别不好;)。我觉得使用协议(与..一起使用)很舒服。你看到不这样做的原因了吗?。顺便说一句,我认为这个答案应该是不正确的。也许我们可以继续我前面的问题。事实上,这一条确实是关于objc_消息发送的,这显然是错误的;创建一个抽象超类,该超类实现始终在子类中实现的方法(如果调用其中任何一个,则抽象甚至可能抛出,从而强制实现)。使用类声明来自
+alloc
的返回类型为
(AbstractClass*)
,并直接调用该方法。这消除了重复协议声明的需要,现在您有了一个地方(抽象超级)来实现公共逻辑,这通常是不可避免的。非常好的建议,谢谢。我会调查的。
@interface NSObject(BobsYourUncle)
- (void)bob:sender;
@end

...

    Class klass = NSClassFromString(@"NSManagedObject");
    [[klass alloc] bob:nil];