目标C链接电话

时间:2014-01-28 20:02:03

标签: objective-c cocoa

我是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类型的临时对象?

3 个答案:

答案 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之前取消分配对象