Cocoa touch 为什么在实例方法中的弱成员在该方法完成之前可以为null?

Cocoa touch 为什么在实例方法中的弱成员在该方法完成之前可以为null?,cocoa-touch,cocoa,automatic-ref-counting,Cocoa Touch,Cocoa,Automatic Ref Counting,为什么调试/发布/模拟器/设备组合会有所不同?(下面是示例代码。) 我继承了一些代码,这些代码可以在模拟器和调试中的设备上“工作”,但不能在发布中的设备上工作(用于上一个LLVM)。它与ARC和一个弱属性(应该是强属性)有关,但我不完全理解发生了什么,我希望有人能向我解释一下,为什么调试/发布/设备/模拟器之间会有所不同 我创建了一个简单的示例项目来演示这一点,AppDelegate.m中的所有代码如下所示。在模拟器中运行时,记录的输出为: -[BaseThingMaker baseMakeTh

为什么调试/发布/模拟器/设备组合会有所不同?(下面是示例代码。)

我继承了一些代码,这些代码可以在模拟器和调试中的设备上“工作”,但不能在发布中的设备上工作(用于上一个LLVM)。它与ARC和一个弱属性(应该是强属性)有关,但我不完全理解发生了什么,我希望有人能向我解释一下,为什么调试/发布/设备/模拟器之间会有所不同

我创建了一个简单的示例项目来演示这一点,AppDelegate.m中的所有代码如下所示。在模拟器中运行时,记录的输出为:

-[BaseThingMaker baseMakeThing]: returning a Thing
-[ThingMaker makeThing]: returning a Thing
-[AppDelegate application:didFinishLaunchingWithOptions:]: got a Thing
-[BaseThingMaker baseMakeThing]: returning a Thing
-[ThingMaker makeThing]: returning a (null)
-[AppDelegate application:didFinishLaunchingWithOptions:]: got a (null)
在设备上运行时,记录的输出为:

-[BaseThingMaker baseMakeThing]: returning a Thing
-[ThingMaker makeThing]: returning a Thing
-[AppDelegate application:didFinishLaunchingWithOptions:]: got a Thing
-[BaseThingMaker baseMakeThing]: returning a Thing
-[ThingMaker makeThing]: returning a (null)
-[AppDelegate application:didFinishLaunchingWithOptions:]: got a (null)
在设备上(调试或发布时),
ThingMaker
中的弱
self.thing
即使在方法完成之前日志消息也是空的。在模拟器上,返回
self.thing
对象

单个窗口应用程序(AppDelegate.m)的示例代码:


方法
baseMakeThing
不返回其调用所拥有的对象,在这种情况下,它返回一个自动释放的对象。如果它是一个自动释放的对象,它将有一个所有者-自动释放池-直到运行循环循环时它清空池。因此,弱属性的赋值将一直有效,直到发生这种情况,并且代码看起来会工作

除非编译器进行优化,否则编译器有时可以将对象从自动释放池中拉出并以这种方式获得所有权,而不是保留自动释放的对象。如果编译器执行此操作,则在为弱属性赋值后,编译器可以立即放弃所有权,因为该引用稍后不会在
makeThing
中使用,这将反过来使弱属性为空


您看到的差异取决于编译器根据构建类型进行了多少优化。

请欣赏答案。这是我的直觉所说的,但看起来很奇怪,弱ivar甚至没有停留足够长的时间来进行NSLog调用。另外,我相信我的问题基本上是重复的。@jefferprice-一旦不再引用编译器,编译器可以自由地删除它的引用,这可能意味着在
NSLog
之前。将
baseMakeThing
的名称更改为
newBaseMakeThing
——按照命名约定,它位于
new
族中,与
init
族类似,它返回一个拥有的对象。现在,您将收到一条警告,在为弱属性赋值后,将立即释放该对象。(你不会得到警告,因为该方法返回的对象不是调用者所拥有的,而不是无人拥有的,因此ARC不负责释放它。)@sbooth-更改名称更容易,但是你可以添加一个属性,但这不是错误的吗?名称更改是为了不返回自动释放的对象,而是返回调用者拥有的对象。@CRD-再次感谢。有趣的是(这意味着我觉得不对),仅仅将方法更改为使用
new
命名约定就足以触发编译器警告(“将保留对象分配给弱属性;对象将在分配后释放”)。感觉上,如果没有
new
,该警告应该发生。当然,如果ivar刚开始时是
strong
,那么一切都可以正常工作。@jefferprice-警告会触发,因为名称更改时所有权会更改,在此之前警告是不正确的。正如您所说,这种行为隐含地依赖于命名,这会使理解更加困难。