我是Objective C的新手,所以如果这个问题看起来很愚蠢,请原谅我。
第一个样本:
int main(int argc, const char* argv[])
{
@autoreleasepool
{
MyCoolDelegate* myCoolDelegate = [[MyCoolDelegate alloc] init];
[[NSApplication sharedApplication] setDelegate: myCoolDelegate];
return NSApplicationMain(argc, argv);
}
}
第二个样本:
int main(int argc, const char* argv[])
{
@autoreleasepool
{
[[NSApplication sharedApplication] setDelegate: [[MyCoolDelegate alloc] init]];
return NSApplicationMain(argc, argv);
}
}
作为C ++程序员,我希望两个主要函数应该具有相同的行为,但是return NSApplicationMain(argc, argv);
上的第二个主要崩溃,而第一个设置委托并按预期工作。
请解释一下这些样品有什么区别?在Objective C中的临时对象周围是否有一些黑魔法(我假设[MyCoolDelegate alloc] init]
将返回MyCoolDelegate
类型的临时对象?
答案 0 :(得分:6)
详细说明@ tenfour的回答,这一行:
MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
其中有一个隐含的“__strong”,所以它的确意味着:
__strong MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
如果您将第一行更改为以下内容:
__unsafe_unretained MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
然后你应该在两种情况下看到相同(坏)的行为。
答案 1 :(得分:5)
你可能想让myCoolDelegate
成为一个实例变量,static
变量,或者在xib文件中创建它(比如你从File> New Project获得的Xcode模板......> Cocoa Application )。
实际上,这两个例子在技术上都是错误的。一个“意外工作”,因为编译器不是(当前!)执行合法优化以在最后一次使用时释放myCoolDelegate
,这是之前的 / em> NSApplicationMain
来电。
Per the spec,“默认情况下,自动存储持续时间的局部变量没有精确的生命周期语义。这些对象只是包含可保留对象指针类型值的强引用,而这些值仍然是完全的受本地控制下的价值优化。“
通常为-setDelegate:
methods don't retain/strongly-reference things,以防止strong reference cycles,其中两个对象彼此之间不会被解除分配。为了兼容性,NSApplication
使用__unsafe_unretained
引用它的delegate
而不是(通常更可取的)__weak
引用(这可能会在将来的OS X版本课程中发生变化)。因此,当NSApplication
在解除分配后尝试与delegate
进行对话时,您会遇到崩溃。 delegate
可以在此处取消分配,因为在-setDelegate:
调用后没有任何内容强烈引用它。
总结:使用隐式临时变量或显式局部变量只保持对象存活,直到变量的最后一次使用。只要变量在范围内,它们就 not 保证对象保持活动状态。遗憾的是,编译器并没有像它那样具有攻击性,这使得一个显式的局部变量似乎延长了对象的生命周期,而不是保证它。如果您启用了更多优化,则可能会看到不同的行为。您需要将myCoolDelegate
变为“更长寿”的变量(ivar,staic
或全局变量),或在声明变量时使用objc_precise_lifetime
属性。
__attribute__((objc_precise_lifetime)) MyCoolDelegate* myCoolDelegate = [[MyCoolDelegate alloc] init];
这种情况很复杂,但实际上并没有出现,因为作为另一个对象的委托的事物几乎总是通过ivar或“长寿”来引用,而不仅仅是局部变量。
答案 2 :(得分:4)
在您的第一个示例中,myCoolDelegate
包含对该对象的引用,使其保持活动状态,直到myCoolDelegate
超出范围,@autoreleasepool
块结束时自动释放已取消分配
在第二个示例中,您创建的MyCoolDelegate
对象不会被任何局部变量保留。您正在创建一个仅在语句持续时间内具有保留计数的临时数。
如果setDelegate
保留该对象,则该对象将继续使用保留计数为1,并且当应用程序尝试使用该应用程序时,您的应用程序不会崩溃。
如果另一方面setDelegate
仅保留弱引用,那么在调用setDelegate
返回后,您的应用程序将因为其保留计数为0而崩溃,因此在NSApplicationMain
之前取消分配对象