【问题标题】:Objective-c pointers magic. Type protectionObjective-c 指针魔术。类型保护
【发布时间】:2026-01-24 23:30:01
【问题描述】:

我有一本字典。 我提取其中一个值如下:

NSString *magicValue= [filterDict valueForKey:[filterDict allKeys][0]];
[SomeClass foo: magicValue];

而 foo 是:

- (void)foo:(NSString*)magicValue
{
    NSLog("magicValue is string:%@",[magic isKindOfClass:[NSString class]] ? @"YES" : @"NO");
    NSLog("magicValue is number:%@",[magic isKindOfClass:[NSNumber class]] ? @"YES" : @"NO");
}

如果字典值为数字,magicValue 将为NSNumber。所以定义的字符串指针将指向NSNumber。日志将返回 yes 进行号码检查。

我从未对此类方法添加保护,以检查“magicValue”是什么类。我假设当我定义一个带有字符串参数的方法时,它将是字符串。

我应该开始考虑这种行为并始终添加检查,还是以这种方式将字典值分配给魔法并使用我的方法的人的错。我需要一些最佳实践建议以及如何处理。

这个问题可能已经回答了,但我不知道如何搜索。

【问题讨论】:

    标签: objective-c pointers types unsafe-pointers


    【解决方案1】:

    简短回答:不,如果没有特殊原因,不要检查。

    长答案:

    你必须区分两种情况:

    A.使用id

    您有一个id 类型的变量或返回值。这是您的示例-valueForKey:。键入的原因是保持方法通用。即使在理论上是可能的,但在实践中,这种情况下的类型不匹配非常罕见,并且在开发过程中可以快速检测到。出于不同的动机,我在一次公开演讲中询问了观众(>200 人),他们在制作过程中有多少次出现这样的打字错误。对于所有听众,他们在所有应用程序版本中的所有应用程序都有 1 个(换句话说:一个!)案例。只需忘记这种风险。这是使用静态类型语言(Java、C++、Swift)的开发人员的焦虑。

    B.分配错误

    如果你没有id 类型,仍然可以做这样的把戏。 (有时您想这样做。这是动态类型的优势。)有两个子类别:

    你可以隐式地做到这一点:

    NSString *string = [NSNumber numberWithInt:1];
    

    编译器会就此发出警告。所以一切都很好,因为开发人员会看到他的错误。您不必保护他或您的代码。

    可以明确地做到这一点:

    NSString *string = (NSString*)[NSNumber numberWithInt:1];
    

    在这种情况下,代码可能会中断。但他明确地做到了。如果它是错误的,开发者有犯罪能量这样做,你不必保护他免受他自己的伤害。

    【讨论】:

      【解决方案2】:

      大多数情况下,您应该知道您引用的是什么类,或者至少知道您希望它是什么类。如果您有一个意外的类,可能会导致崩溃,具体取决于您发送给它的消息,您可以调试您的代码并获得正确的参考。

      有时,通常在处理继承时,您需要在运行时而不是在编译时确定类。这时候,isKindOfClass: 会很有用。如果您知道一个值可能是许多类之一,我会将其提取为id,然后在最后一刻将其转换为例如

      id value = [[NSUserDefaults standardUserDefaults] valueForKey:aKey];
      if ([value isKindOfClass:[MyClass class]]) {
          // Do one thing
      }
      else {
          // Do another
      }
      

      【讨论】: