ios - 在 Objective-C 中检查方法参数的最佳方法是什么?

标签 ios objective-c macos

在编码方法或函数时,检查输入参数以响应任何可能的失败情况是一种很好的做法。

例如:

-(void)insertNameInDictionary:(NSString*)nameString
{
    [myDictionary setObject:nameString forKey:@"Name"];
}

这看起来不错,但如果 nameStringnil ,应用程序将崩溃。所以,我们可以检查它是否是 nil , 对?。我们还可以检查它是否是 NSString 而不是 NSNumber 或者它是否响应我们的方法需要调用的方法。

所以我的问题是:检查这些论点的最完整和最优雅的方法是什么?

最佳答案

有多种方法可以实现这种保护:

  • NSParameterAssert
  • __attribute__((nonnull))
  • 和一个简单的 if测试。

  • [编辑]
    从最新的 Xcode 版本 (Xcode 6) 开始,Apple 添加了 nullability annotations这是表达参数是否可以是 nil 的另一种——也是更好的——方式/null或不。您应该迁移到该符号而不是使用 __attribute__((nonnull))使您的 API 更具可读性。

    详细说明:
  • NSParameterAssert是 Apple 的专用宏,用于检查方法参数的条件并在失败时抛出专用异常。
  • 这是一个 仅在运行时提供保护
  • 这个宏还在认为通过 nil作为参数是编程/概念错误 ,考虑到由于您的应用程序工作流程,它通常永远不会发生(例如,由于其他条件确保参数永远不会是 nil),并且如果它不是真的出了问题。
  • 它仍然会抛出一个异常(如果需要,您的调用代码可能是 @try/@catch),但它的优点是抛出的异常更加明确(告诉参数预计不是 nil 而不是因丑陋而崩溃)难以理解的调用堆栈/消息)。
  • 如果您想允许您的代码使用 nil 调用您的方法但在这种情况下什么都不做,你可以简单地if (!param) return在函数/方法的开头。
  • 这考虑到通过 nil不是编程/概念错误,因此有时可能由于应用程序的工作流程而发生,因此这是可能发生的可接受的情况,但不应崩溃。
  • 鲜为人知,there is the __attribute__((nonnull)) GCC/LLVM attribute专用于告诉编译器某个函数/方法的某些参数预计不为空 .这样,如果编译器可以在编译时检测到您尝试使用 nil 调用您的方法/函数/NULL参数(比如直接调用 insertNameInDitionary:nil 而不是使用一个在编译时还不能确定值的变量),它会立即发出编译错误让你尽快修复它。
  • [编辑] 从最新的 Xcode 6 开始,您可以(并且应该)使用 nullability annotations而不是 __attribute__((nonnull)) .请参阅 Apple 博客文章中的示例。


  • 所以总结一下:

    如果你想标记你的方法 EXPECT 你的参数是非 nil ,从而表明用 nil 调用它是逻辑错误,您应该执行以下操作:
    - (void)insertNameInDictionary:(NSString*)nameString __attribute__((nonnull))
    {
        // __attribute__((nonnull)) allows to check obvious cases (directly passing nil) at compile time
        NSParameterAssert(nameString); // NSParameterAssert allows to check other cases (passing a variable that may or may not be nil) at runtime
        [myDictionary setObject:nameString forKey:@"Name"];
    }
    

    如果您认为 使用 nil 调用您的方法可能发生并且是可以接受的 ,并且您只想避免在这些情况下崩溃,只需执行以下操作:
    -(BOOL)insertNameInDictionary:(NSString*)nameString
    {
        if (nameString == nil) return NO;
        [myDictionary setObject:nameString forKey:@"Name"];
        return YES;
    }
    

    如果您认为 你应该可以插入一个 nil字典中的对象 ,您可以转换 nil值到 NSNull在这种特定情况下,插入 NSNull专用于此类用途的单例(我使用了 ?: 三元运算符的简短形式来使代码更紧凑):
    -(void)insertNameInDictionary:(NSString*)nameString
    {
        [myDictionary setObject:nameString?:[NSNull null] forKey:@"Name"];
    }
    

    最后一种情况,如果你想通过 nil在那个特定的例子中,简单地删除了 Name来自 myDictionary ,你可以简单地做一个简单的 if测试并调用 removeObjectForKey:@"Name"如果 nameStringnil并调用 setObject:forKey:如果不是……或者您可以使用 KVC 和通用 setValue:forKey: (KVC 方法,根本不特定于 NSDictionary,所以不要与 setObject:forKey: 混淆)在 NSDictionary 的情况下完全具有相同的行为(如果我们通过 nil 作为 value 参数,则从字典中删除键) .

    关于ios - 在 Objective-C 中检查方法参数的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21054024/

    相关文章:

    ios - iOS 13.4 上未更改的 barTintColor UINavigationBar

    ios - 动画调整 UIView 和 subview 大小的更好方法?

    iphone - NSFetchedResultsController 的 sectionNameKeyPath 不工作

    macos - 从我的 mac 访问 tomcat web 服务器时出错

    c++ - 如何在 Mac 上编写 C++?

    iphone - iOS - 以编程方式在 TableRow 的右侧添加 ToggleSwitch

    ios - 自定义推送通知

    ios - 将 SceneKit 场景渲染到视频输出

    linux - 如何检查前一次运行是否失败?

    ios - 在 Swift 中更改 guard 语句中的变量?