6

我有一个偶尔会崩溃的方法。

-(void)foo{
    [self doSomething];
    [self.delegate didFinish];
    [self doSomethingElse];
}

-doSomething 工作正常,然后我调用委托 -didFinish。在 -didFinish 中,对该对象的引用可能设置为 nil,在 ARC 下释放它。当方法崩溃时,它会在 -doSomethingElse 上执行此操作。我的假设是 self 在方法中会很强大,从而允许函数完成。自己是弱还是强?有这方面的文件吗?它强或弱的原因是什么?

编辑

在受到以下一些答案的启发后,我进行了一些调查。在我的案例中,崩溃的实际原因是 NSNotificationCenter 在任何情况下都没有保留观察者。Mike Weller 在下面指出,方法的调用者应该在调用对象时保留对象,以防止我上面描述的情况,但是 NSNotificationCenter 似乎忽略了这个问题,并且始终保持对观察者的弱引用。换句话说:

-(void)setupNotification{
    //observer is weakly referenced when added to NSNotificationCenter
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleNotification:)
                                                 name:SomeNotification object:nil];
}

//handle the notification
-(void)handleNotification:(id)notification{
    //owner has reference so this is fine
    [self doSomething];
    //call back to the owner/delegate, owner sets reference to nil
    [self.delegate didFinish];
    //object has been dealloc'ed, crash
    [self doSomethingElse];
}
4

2 回答 2

9

self 在方法中是强的,允许函数完成。自己是弱还是强?

self在ARC中既不强也不弱。假设调用者持有一个引用,并且self是不安全的 unretained

self在 ARC 下可以在其自己的方法中进行编辑也是如此-dealloc,并且它被视为您的程序执行此操作的“未定义行为(或至少是危险的)”。

它强或弱的原因是什么?

对于性能而言,它是未保留的——以避免(在绝大多数情况下)不必要的引用计数 inc/dec。即使他们执行了所有这些额外的引用计数操作,您的程序在多线程程序或存在竞争条件(也包括 UB)的情况下仍然容易受到此类问题的影响。所以这是他们(正确地)确定他们不需要为自己辩护的极端情况之一。

有这方面的文件吗?

当然!:)

于 2013-08-02T07:52:24.377 回答
5

self既不弱也不强。如果您可以访问self,那么您就在方法调用的范围内,并且该方法调用是由某人通过他们必须拥有的引用执行的。self只要它在范围内,就暗示它是一个有效的引用,并且暗示任何内存管理或所有权都由调用者处理。

通过弱引用调用方法时,ARC 将在该方法调用期间保留对象(请参阅此答案)。启用严格的编译器警告后,您实际上将被迫在向该引用发送任何方法之前创建一个强引用。

因此,根据定义,如果在对象上调用方法,则调用者必须已经拥有所有权,并且无​​需执行任何操作。

当然,最终可能会在已释放的对象上调用方法,但这是调用者代码错误的结果。

于 2013-08-01T14:29:40.033 回答