【问题标题】:How to return any type value like -performSelector?如何返回任何类型值,如 -performSelector?
【发布时间】:2014-07-16 11:15:51
【问题描述】:

-performSelector 方法的返回类型是id,我在 Apple 文档中找到了这个:

For methods that return anything other than an object, use NSInvocation.

但下面的代码运行良好:

BOOL boolValue = (BOOL)[self performSelector:@selector(boolValue)];

它可以返回idBOOLNSInteger等。我想知道怎么做?因为将BOOLNSInteger转换为id在return语句中导致错误:

Cast of 'NSInteger' (aka 'long') to 'id' is disallowed with ARC

提前致谢!

----编辑----

感谢您的回答。

我知道这样做不好,我也知道如何使用NSInvocation,我只想知道-performSelector方法是如何实现的。

----编辑----

终于找到了……

https://opensource.apple.com/source/objc4/objc4-706/runtime/NSObject.mm

【问题讨论】:

  • object 强制转换为 primitive 在逻辑上并不正确。
  • @holex 是的,我知道。我只是想知道该怎么做。
  • 您只能发回一个 object,例如 NSNumber,您可以在其中存储一个 primitive 值,例如BOOLNSIntegerFloat64 等等......当你拥有对象时,你可以将它转换回 primitives。既不太优雅也不太安全——但很快。

标签: objective-c


【解决方案1】:

除了在其他答案中使用NSInvocation外,如果您在编译时知道类型,也可以直接使用调用实现函数。

SEL sel = @selector(boolValue);
IMP imp = [self methodForSelector:sel];
BOOL value = ((BOOL (*)(id, SEL))imp)(self, sel);

您必须将imp 转换为正确的类型,否则它是未定义的行为,如果幸运的话会崩溃。

【讨论】:

  • 这是 32 位/64 位和 ARC 最安全的方法,因为可以通过这种方式指定每个参数的确切大小以及是否应该传递 strongweak
【解决方案2】:

获取返回值的最佳方式,使用NSInvocation,而不是执行选择器。下面是example:-

SEL selector = NSSelectorFromString(@"someSelector");
if ([someInstance respondsToSelector:selector]) {
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
                                [[someInstance class] instanceMethodSignatureForSelector:selector]];
    [invocation setSelector:selector];
    [invocation setTarget:someInstance];
    [invocation invoke];
    float returnValue;
    [invocation getReturnValue:&returnValue];
    NSLog(@"Returned %f", returnValue);
}

【讨论】:

    【解决方案3】:

    首先,您的代码不起作用:要查看它是如何损坏的,请在 64 位系统上运行它。在 32 位系统上,它在一个不幸的事故中运行,but on 64-bit systems the upper half of the returned value will contain garbage data。这是因为在将结果返回给您之前,BOOL 将被强制转换为 id,这将导致未定义的行为。

    要正确操作,请查看 Stack Overflow 上的众多答案之一 - 例如,this one

    【讨论】:

    • 我不推荐NSInvocation。使用 ARC 很难做到正确,例如使用 __autoreleasing(例如 (NSError **)error)。
    【解决方案4】:

    您编写的代码之所以有效,是因为您滥用了类型。选择器 boolValue 返回的 BOOL 被强制转换为 id,然后再转换为 BOOL。这是有风险的,因为不保证 id 字段的长度与 BOOL 的长度相同。

    ARC 对 id 返回类型进行了额外的处理,因此这种滥用根本不起作用,这就是您收到编译错误的原因。有一个桥接技巧应该可以使它工作,但我在这里犹豫重复它,因为它完全没有必要并且会导致真正糟糕的代码。

    有关执行此操作的正确方法的更多详细信息,请参阅此问题:iPhone: performSelector with BOOL parameter?

    【讨论】:

      猜你喜欢
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多