简体   繁体   English

如何正确通知委托人该实例不再需要?

[英]How to correctly notify a delegate that the instance is no longer needed?

This is my pattern: 这是我的模式:

1) SpecialView creates a MessageView and holds a strong reference to it. 1)SpecialView创建一个MessageView并对其进行强有力的引用。

2) User taps a button in MessageView which causes it to fade out. 2)用户在MessageView中点击一个按钮,使其淡出。 MessageView then tells it's delegate, SpecialView, that it faded out completely. 然后,MessageView告诉它的委托SpecialView,它完全消失了。

3) SpecialView releases MessageView. 3)SpecialView发布MessageView。

The problem is this: 问题是这样的:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    [self.delegate messageViewFadedOut:self]; // delegate releases us...
    // self maybe got deallocated... BOOM!
    // now what? method of a zombie returns? stack freaks out?
} // does it even return?

In the last line I'm calling the delegate, which in turn immediately releases MessageView. 在最后一行中,我将调用委托,委托将立即释放MessageView。 -fadedOut:finished:context: is called by a core animation didStopSelector callback. -fadedOut:finished:context:由核心动画didStopSelector回调调用。

My fear is that the MessageView instance is going to be deallocated immediately before the -fadedOut:finished:context: fully returned, causing very nasty random bugs 我担心的是,MessageView实例将在-fadedOut:finished:context:完全返回之前立即被释放,从而导致非常讨厌的随机错误

Once upon a time, a old veteran programmer told me: "Never cut the branch on which you're sitting on." 很久很久以前,一位资深的资深程序员告诉我:“切勿割断您所坐的树枝。”

So in order to make sure the instance survives until this method returns, I made a retain-autorlease-dance before calling the delegate: 因此,为了确保实例在此方法返回之前一直存在,我在调用委托之前做了一次retain-autorlease-dance。

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    //[[self retain] autorelease];
    [self.delegate messageViewFadedOut:self]; // delegate releases us...
}

However, under ARC, retain-autorelease dances are not allowed anymore (the migration tool won't allow it) and there seems to be no way to force the ARC system to do something like this. 但是,在ARC下,不再允许保留-自动释放的舞蹈(迁移工具将不允许),并且似乎没有办法强制ARC系统执行类似的操作。

So I came up with this strategy instead: 所以我想出了这个策略:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    [self.delegate performSelector:@selector(messageViewFadedOut:) withObject:self afterDelay:0];
}

The delayed performSelector hopefully lets the method fully return. 延迟的performSelector有望使方法完全返回。 As far as I know a delay of 0 still guarantees that the selector is performed in the next run loop iteration rather than immediately. 据我所知,延迟为0仍保证选择器在下一个运行循环迭代中执行,而不是立即执行。

There's a good chance this is bogus as well. 这很有可能也是伪造的。

How can I correctly resolve this problem of one object asking another to destroy the last reference to it with the chance that the object get's deallocated before the method that made the call to the other object has a chance to fully return? 我该如何正确地解决这个问题,即一个对象要求另一个对象销毁对它的最后一个引用,从而有可能在调用另一个对象的方法有机会完全返回之前将对象重新分配? Can there be something like a stack trace zombie? 会有像堆栈跟踪僵尸这样的东西吗?

And how must I solve something like this under ARC? 在ARC下如何解决类似问题?

To be honest, I think that rather than trying to emulate a retain-autorelease, you should make sure that by the time the delegate method messageViewFadedOut: is called you don't care if the owning reference to your message view is released. 坦白地说,我认为与其尝试模仿保留自动释放,还应确保在调用委托方法messageViewFadedOut:不要在意是否释放了对消息视图的拥有引用。 The contract for a willFadeOut: method may assume it won't be deallocated, but a fadedOut: or didFadeOut: method should be okay with the object being deallocated. willFadeOut:方法的willFadeOut:可能会假设它不会被取消分配,但是fadedOut:didFadeOut:方法对于被取消分配的对象应该没问题。

An ideal solution would be for your dealloc method to specifically avoid the nasty random bugs you are dreading, by cancelling any active fadeout animation that is occurring (hold a reference to it somewhere). 一个理想的解决方案是,通过取消正在发生的任何活动淡入动画(将引用保留在某个地方), dealloc方法可以特别避免可怕的令人讨厌的错误。 That way you don't care how or when it gets to dealloc , because dealloc knows to do X to prevent leaving any object state or visual anomalies behind when it dies. 这样一来,您就不必在乎如何或何时使用dealloc ,因为dealloc知道这样做X是为了防止在死时留下任何对象状态或视觉异常。

So just use your solution ( performSelector:withObject:afterDelay: ) or maybe a GCD block: 因此,只需使用您的解决方案( performSelector:withObject:afterDelay:或一个GCD块:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 250 * NSEC_PER_MSEC), // 250ms
                   dispatch_get_current_queue(),
                   ^{
                        [self.delegate messageViewFadedOut:self];
                   });
}

Besides, ARC might just autorelease immediately, why don't you test that code section a bunch of times and see what happens? 此外,ARC可能会立即autorelease ,为什么不多次测试该代码段并查看会发生什么呢? Put a breakpoint in dealloc and see if it's called before the method returns. dealloc放置一个断点,看看在方法返回之前是否调用了该断点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM