在UIViewController中使NSTimer无效以避免保留周期的最佳时机

MyC*_*ner 33 iphone memory-leaks memory-management objective-c nstimer

有没有人知道何时是停止在UIViewController内部保持引用的NSTimer的最佳时间,以避免在定时器和控制器之间保留周期?

这是更详细的问题:我在UIViewController中有一个NSTimer.

在视图控制器的ViewDidLoad期间,我启动计时器:

statusTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: self selector: @selector(updateStatus) userInfo: nil repeats: YES];
Run Code Online (Sandbox Code Playgroud)

以上导致计时器保持对视图控制器的引用.

现在我想释放我的控制器(例如父控制器释放它)

问题是:我可以在哪里调用[statusTimer invalidate]来强制定时器释放对控制器的引用?

我尝试将它放在ViewDidUnload中,但是在视图收到内存警告之前不会被触发,所以不是一个好地方.我尝试了dealloc,但只要计时器还活着(鸡蛋和鸡蛋问题),dealloc就永远不会被调用.

有什么好建议吗?

Jer*_*man 21

  1. 您可以通过以下方式避免保留周期:例如,将计时器瞄准StatusUpdate对象,该对象保存对控制器的非保留(弱)引用,或者通过StatusUpdater控制器指针初始化,保持弱引用为此,并为您设置计时器.

    • 您可以让视图-willMoveToWindow:在目标窗口nil(应该处理-viewDidDisappear:您提供的反例)以及其中时停止计时器-viewDidDisappear:.这意味着您的视图将重新回到您的控制器中; 你可以通过向控制器发送-view:willMoveToWindow:信息或发布通知来避免进入计时器,如果你愿意的话.

    • 据推测,您是导致视图从窗口中移除的那个,因此您可以添加一行来停止计时器以及驱逐视图的线.

    • 您可以使用非重复计时器.一旦它发射它将立即失效.然后,您可以在回调中测试是否应创建新的非重复计时器,如果是,则创建它.然后,不需要的保留周期将仅保持定时器和控制器对,直到下一个发火日期.只需1秒的开火日期,您就不必担心了.

每个建议,但第一个是与保留周期一起生活并在适当的时间打破它的方式.第一个建议实际上避免了保留周期.


Pet*_*eas 6

解决它的一种方法是让NStimer保持对你的UIViewController的弱引用.我创建了一个类,它包含对象的弱引用,并将调用转发给:

#import <Foundation/Foundation.h>

@interface WeakRefClass : NSObject

+ (id) getWeakReferenceOf: (id) source;

- (void)forwardInvocation:(NSInvocation *)anInvocation;

@property(nonatomic,assign) id source;

@end

@implementation WeakRefClass

@synthesize source;

- (id)init{
    self = [super init];
//    if (self) {
//    }
    return self;
}

+ (id) getWeakReferenceOf: (id) _source{

    WeakRefClass* ref = [[WeakRefClass alloc]init];
    ref.source = _source; //hold weak reference to original class

    return [ref autorelease];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [[self.source class ] instanceMethodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    [anInvocation    invokeWithTarget:self.source ];

}

@end
Run Code Online (Sandbox Code Playgroud)

你像这样使用它:

statusTimer = [NSTimer scheduledTimerWithTimeInterval: 1 target: [WeakRefClass getWeakReferenceOf:self] selector: @selector(updateStatus) userInfo: nil repeats: YES];
Run Code Online (Sandbox Code Playgroud)

你的dealloc方法被调用(与之前不同),你只需调用它:

[statusTimer invalidate];
Run Code Online (Sandbox Code Playgroud)