【问题标题】:What does "sending a message to nil" mean, and why is it a special case? [duplicate]“向 nil 发送消息”是什么意思,为什么是特例? [复制]
【发布时间】:2010-11-07 15:24:05
【问题描述】:

刚开始看Objective-C的教程,有一节是“给nil发消息”:

Cocoa 中有几种模式 利用这一事实。这 从消息返回到 nil 的值 也可能有效:

这是什么意思?我好像跟不上。

【问题讨论】:

    标签: objective-c null


    【解决方案1】:

    您可以向 nil 发送任何消息。什么都没发生。

    您在这些文档中到底有哪些不明白的地方?

    【讨论】:

    • 什么是零?您是否将值 null 设置为对象的方法?或将值 null 发送到消息?什么信息?
    • "nil" 是一个空对象。如果您熟悉 Java,“向 nil 发送消息”相当于 Java 中的“在 null 上调用方法”,除了在 Java 中,您会得到 NullPointerException,而在 Objective-C 中,什么都不会发生。因此,您可以安全地执行“[nil doThis:withThis]”之类的操作,并且程序不会崩溃(该方法只会返回 nil)。
    • 不完全是。 Nil 等于 0,它不是一个对象。这就是为什么您可以对返回整数值的方法做同样的事情。有一个特殊的 NSNull 对象可以在集合类中使用,但它不等于 nil。
    • @Marc:所有对象都等于某个整数。您可以向 nil 发送消息(这对每个对象都是正确的,而在 Objective-C 中对非对象不正确),因此至少从概念上讲,nil 可以有意义地称为对象。不过,这是一个特殊的值。
    • "nil" 通常是指一个 nil 实例,而 "Nil" 通常是指 nil 类。我认为在 GNU 运行时它们实际上是显式转换 (id)0 和 (Class)0,但我目前只能访问 NS 运行时。 10.5 之前的运行时将 nil 和 Nil 定义为 0,但 10.5 将它们定义为 __DARWIN_NULL。
    【解决方案2】:

    它做你所期望的:什么都没有。

    【讨论】:

    • 熟悉 Java、C# 或 C++ 等流行语言的人很少会期望这无济于事。他们预计会出现异常或崩溃。
    【解决方案3】:

    nil 的特殊处理意味着您可以执行以下操作:

    SomeClass * someObject;
    someObject = nil;
    [someObject doSomething];
    

    您可以放心,不会发生任何事情。

    现在,为什么这很重要?

    在 Objective-C 中,向对象发送消息意味着告诉该对象做某事,或要求该对象提供一些信息。一些例子:

    [someObject updateRecords]; // 1
    x = [someObject size];      // 2
    

    第 1 行向 someObject 发送一条名为 updateRecords 的消息,第 2 行向同一对象发送一条名为 size 的消息,该消息预计会返回一个值。这些消息归结为方法调用,最终运行的实际代码由 Objective-C 运行时系统确定,因为 Objective-C 是一种动态类型语言。

    为了确定调用哪个方法,运行时系统从相关对象的地址(someObject,在上面的示例中)读取信息,以确定它是哪个类的实例。使用这些信息,它能够查找要调用的适当方法,当所有这些都弄清楚后,它就会执行方法中的代码。

    如果运行时系统没有将nil 视为特殊情况,如果您尝试执行顶部显示的代码,它可能会崩溃。 nil 被定义为零,因此运行时将从存储在内存中位置零的地址开始读取信息,这几乎可以保证是访问冲突。

    【讨论】:

    • 那么为什么在raywenderlich.com/2696/… 中,他们说“向释放的内存发送消息会导致崩溃”?
    • 如果您释放一个对象但仍保留指向旧内存位置的指针,则可能会向已释放内存(也称为僵尸)发送消息。例如:[someObject release]; [someObject someMethod];。这与someObject = nil; [someObject someMethod]; 非常不同@ 即使将 someObject 设置为 nil 可能会在 GC 环境中释放它,但将其设置为 nil 的行为也会阻止您向 deallocated 内存发送消息。
    【解决方案4】:

    与 C# 等其他语言相比,nil 消息传递的好处在于,您可以编写执行多个方法调用的代码,而无需在每一步都测试 nil。

    id obj1 = [SomeClass object];
    id obj2 = [obj1 doSomething];
    id obj3 = [obj2 anotherMethod];
    
    id thingICareAbout = [obj3 doSomethingElse];
    

    如果你通过几个步骤到达thingICareAbout,它会节省很多不必要的代码行,而不必在使用之前测试obj1、obj2等是否为nil。如果需要,您可以在最后检查 thingICareAbout 是否为 nil 一次。有时您甚至不必这样做,如果您的代码在其为 nil(或原始值为 0)时仍然有效。

    在 C# 中,您必须明确检查每个对象是否为 nil,围绕该代码块设置异常处理,或者只是希望中间对象都不是 nil。

    要记住的另一件事(我刚刚学会了!)是 10.5 改变了这种行为——过去它只对整数和指向对象的指针是安全的,而不是结构或浮点值。因此,当您查看其他代码时,您可能会看到一些额外的错误检查。

    【讨论】:

      【解决方案5】:
      • nil 基本上是一个空指针(即它是存储在指针中的数字零)。
      • 所有发给 nil 的消息都是合法的(它们不会导致崩溃),但它们什么都不做。
      • 所有发送到 nil 的消息都返回 nil、0、0.0 或 NO,具体取决于返回类型。

      【讨论】:

      • 第 3 点取决于运行时。在较早的运行时,文档说如果方法返回浮点数、双精度数或大于自然字大小的变量,则不能依赖消息传递 nil 的返回值。
      猜你喜欢
      • 1970-01-01
      • 2019-03-30
      • 2016-07-14
      • 2020-10-27
      • 2015-07-15
      • 2018-07-17
      • 2012-08-13
      • 2019-09-12
      相关资源
      最近更新 更多