【问题标题】:Changing a default returned id to an NSTimeInterval将默认返回的 id 更改为 NSTimeInterval
【发布时间】:2014-07-10 14:34:18
【问题描述】:

我有一段代码调用一个对象的方法,该对象的 .h 文件我没有包含在我的项目中,也不能包含(我不想进入这个)。

但是,我知道我需要调用它所具有的特定函数,该函数返回 NSTimeInterval

显然,编译器警告我该方法未定义并且可能会崩溃。问题是编译器将未知函数的返回值默认为 id,我无法将 id 强制转换为非指针值。然而,在运行时,id 的值是我需要 NSTimeInterval 包含的值。

id tempValue = [myObject unknownNumberMethod]; // compiler says: "instance method -unknownNumberMethod not found(return type defaults to 'id'
NSTimeInterval realValue = (NSTimeInterval)tempValue; //this yields a compilation error:/Users/Niv/Projects/Copia/Copia.MAC/RMSDKServicer/RMSDKServicer/Downloader/ActivatorService.m:75:24: Initializing 'NSTimeInterval' (aka 'double') with an expression of incompatible type 'id'

我尝试声明这样的方法,只是为了让编译器理解它返回一个NSTimeInterval而不是id

@interface MyClass //type of myObject
-(NSTimeInterval)unknownNumberMethod;
@end

然而,这使得unknownNumberMethod 不断地返回0,所以我假设它用空白覆盖了真正的方法。

我还寻找了一些方法来定义一个类的extern 方法,但找不到正确的语法。

什么是“强制”编译器意识到即使它没有找到方法定义,它返回一个NSTimeInterval而不是id的正确方法?

【问题讨论】:

  • 您不认为找出为什么编译器抱怨-unknownNumberMethod 会更好吗?你真的认为你能从中获得任何有用的价值吗?
  • 老实说,在运行时我可以看到 id 的值是正确的。
  • 我相信更聪明的人可以对此进行改进,但是您可以从 [NSString stringWithFormat@"%p", returnValue] 获得一个具有十六进制值的 NSString

标签: objective-c nstimeinterval


【解决方案1】:

使用 NSInvocation 对象而不是 performSelector 调用。见NSInvocation documentation

【讨论】:

    【解决方案2】:

    你试过了吗?

    SEL selector = NSSelectorFromString(@"unknownNumberMethod");
    if ([someInstance respondsToSelector:selector]) {
        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:
                                [[myObject class] instanceMethodSignatureForSelector:selector]];
        [invocation setSelector:selector];
        [invocation setTarget:myObject];
        [invocation invoke];
        NSTimeInterval realValue;
        [invocation getReturnValue:&realValue];
    }
    

    【讨论】:

    • realValue 中的结果为 0,而从 gdb 调用该函数显示的是真实值
    【解决方案3】:

    重申我的评论,也许这是一个坏主意,但可能可行的一件事是使用字符串格式化操作 %p 将 id 呈现为十六进制 NSString,然后将其解释为双精度...

    id tempValue = [myObject unknownNumberMethod]; // compiler says: "instance method -unknownNumberMethod not found(return type defaults to 'id'
    NSString *yuck = [NSString stringWithFormat:@"%p", tempValue];
    
    NSTimeInterval result;
    NSScanner *scanner = [NSScanner scannerWithString:yuck];
    [scanner scanHexDouble:&result];
    

    【讨论】:

      【解决方案4】:

      如果您无权访问头文件,正确的做法是在非正式协议中提供您自己的方法声明:

      @interface NSObject(MyAppExtension)
      - (NSTimeInterval)unknownNumberMethod;
      @end
      

      然后像调用其他方法一样调用该方法:

      id foo = ... 
      
      NSTimeInterval timeInterval = 0.0;
      if ([foo respondsToSelector:@selector(unknownNumberMethod)]) {
          timeInterval = [foo unknownNumberMethod];
          NSLog(@"Got Time Interval: %f", timeInterval);
      }
      

      这使得 unknownNumberMethod 不断返回 0,所以我假设它用一个空白的方法覆盖了真实的方法。

      这是不正确的;什么都没有被覆盖。一个对象要么提供给定选择器的实现,要么不提供。

      如果它没有返回您期望的值,则说明该方法的返回类型不正确。尝试将方法声明中的返回类型更改为floatvoid*。在 32 位和 64 位系统上,返回 void* 的方法与返回 id 的方法具有相同的调用约定。

      (如果您正在为 32 位 iOS 编译,这可以解释为什么 id 有效而 NSTimeInterval 无效。将返回类型声明为 float。)

      【讨论】:

      • 我正在为 32 位 osx 编译,在 xpc 服务中。该解决方案似乎适用于 NSString,但是在 timeInterval 中仍然得到 0。如果我在赋值行中断并打印出赋值的右值,我会得到正确的值。
      • 浮点值通常通过 x87 浮点寄存器返回。您的方法似乎没有发生这种情况(即,它通过常规的 32 位寄存器返回)。要获取返回值,您需要将返回类型声明为非浮点 32 位值(如指针)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多