我是Objective C的新手,所以如果这个问题看起来很愚蠢,请原谅我.
第一个样本:
int main(int argc, const char* argv[])
{
@autoreleasepool
{
MyCoolDelegate* myCoolDelegate = [[MyCoolDelegate alloc] init];
[[NSApplication sharedApplication] setDelegate: myCoolDelegate];
return NSApplicationMain(argc, argv);
}
}
Run Code Online (Sandbox Code Playgroud)
第二个样本:
int main(int argc, const char* argv[])
{
@autoreleasepool
{
[[NSApplication sharedApplication] setDelegate: [[MyCoolDelegate alloc] init]];
return NSApplicationMain(argc, argv);
}
}
Run Code Online (Sandbox Code Playgroud)
作为C++程序员,我希望两个主要函数都应该具有相同的行为,但是第二个主要崩溃时return NSApplicationMain(argc, argv);
,第一个设置委托并按预期工作.
你能解释一下这些样品有什么区别吗?在Objective C中的临时对象周围是否有一些黑魔法(我假设[MyCoolDelegate alloc] init]
会返回一个类型的临时对象MyCoolDelegate
)?
详细说明@ tenfour的答案,这一行:
MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
Run Code Online (Sandbox Code Playgroud)
其中有一个隐含的"__strong",所以它的确意味着:
__strong MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
Run Code Online (Sandbox Code Playgroud)
如果您将第一行更改为以下内容:
__unsafe_unretained MyCoolDelegate *myCoolDelegate = [[MyCoolDelegate alloc] init];
Run Code Online (Sandbox Code Playgroud)
然后你应该在两种情况下看到相同(坏)的行为.
您可能想要创建myCoolDelegate
一个实例变量,static
变量,或者在xib文件中创建它(就像您从File> New Project ...> Cocoa Application那样获得的Xcode模板).
实际上,这两个例子在技术上都是错误的.一个"意外工作",因为编译器没有(当前!)执行合法优化myCoolDelegate
,以便在NSApplicationMain
呼叫之前的最后一次使用时立即释放.
根据规范,"默认情况下,自动存储持续时间的局部变量没有精确的生命周期语义.这些对象只是包含可保留对象指针类型值的强引用,并且这些值仍然完全受本地值下的值的优化影响.控制."
通常,-setDelegate:
方法不会保留/强引用事物,以防止强引用循环,其中两个对象都保持彼此不被释放.为了兼容性,NSApplication
使用__unsafe_unretained
对它的引用delegate
而不是(通常是可取的)__weak
引用(这可能在将来的OS X版本过程中发生变化).因此,当它被解除分配后NSApplication
试图与它交谈时delegate
,你会崩溃.在delegate
这里可以释放,因为没有什么是后强烈引用它-setDelegate:
的呼叫.
总结:使用隐式临时变量或显式局部变量只保持对象存活,直到变量的最后一次使用.只要变量在范围内,它们就不能保证对象保持活动状态.遗憾的是,编译器并没有像它那样具有攻击性,这使得一个显式的局部变量似乎延长了对象的生命周期,而不是保证它.如果您启用了更多优化,则可能会看到不同的行为.您需要创建myCoolDelegate
一个"更长寿"的变量(ivar staic
,或全局)或objc_precise_lifetime
在声明它时使用该属性.
__attribute__((objc_precise_lifetime)) MyCoolDelegate* myCoolDelegate = [[MyCoolDelegate alloc] init];
Run Code Online (Sandbox Code Playgroud)
这种情况很复杂,但实际上并没有出现太多,因为作为另一个对象的委托的事物几乎总是通过ivar或"长寿"来引用,而不仅仅是局部变量.
归档时间: |
|
查看次数: |
163 次 |
最近记录: |