iphone - 如何知道何时使 `NSTimer` 无效

标签 iphone ios objective-c automatic-ref-counting nstimer

这是我的问题:

我有一个模型类,其中有一个 NSTimer,我希望 Timer 在模型对象的整个生命周期内运行。初始化很简单:我只需在 init 方法中添加以下代码行:

self.maintainConnectionTimer = 
             [NSTimer scheduledTimerWithTimeInterval:1 
                                              target:self 
                                            selector:@selector(maintainConnection) 
                                            userInfo:nil 
                                             repeats:YES];

但是,我的问题是,当模型从内存中释放时,我如何使这个计时器失效?现在,这通常很容易,但是,据我所知,当您安排一个NSTimer 操作系统维护一个指向 Timer 对象的强指针。

我该如何处理?是否有在模型从内存中释放之前立即调用的方法?

最佳答案

[NSTimer scheduledTimerWithTimeInterval:...] 保留目标,所以如果目标是self,那么你的模型实例类永远不会被释放。

作为一种解决方法,可以使用单独的对象(在以下示例中称为 TimerTarget)。 TimerTargetModelClass 有一个引用,以避免循环保留。

这个“助手类”看起来像这样。它的唯一目的是将定时器事件转发给“真正的目标”。

@interface TimerTarget : NSObject
@property(weak, nonatomic) id realTarget;
@end

@implementation TimerTarget

- (void)timerFired:(NSTimer*)theTimer
{
    [self.realTarget performSelector:@selector(timerFired:) withObject:theTimer];
}

@end

现在,在您的模型类中,您可以创建一个计时器并在 dealloc 中使它无效:

@interface ModelClass ()
@property(strong, nonatomic) NSTimer *timer;
@end

@implementation ModelClass

- (id)init
{
    self = [super init];
    if (self) {
        TimerTarget *timerTarget = [[TimerTarget alloc] init];
        timerTarget.realTarget = self;
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1
                                                 target:timerTarget
                                               selector:@selector(timerFired:)
                                               userInfo:nil repeats:YES];
    }
    return self;
}

- (void)dealloc
{
    [self.timer invalidate]; // This releases the TimerTarget as well!
    NSLog(@"ModelClass dealloc");
}

- (void)timerFired:(NSTimer*)theTimer
{
    NSLog(@"Timer fired");
}

@end

所以我们有

modelInstance ===> timer ===> timerTarget ---> modelInstance
(===> : strong reference, ---> : weak reference)

请注意,不再有从计时器到模型类实例的(强)引用。

我用下面的代码对此进行了测试,它创建了一个 ModelClass 的实例并在 5 秒后释放它:

__block ModelClass *modelInstance = [[ModelClass alloc] init];
int64_t delayInSeconds = 5.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    modelInstance = nil;
});

输出:

2013-01-23 23:54:11.483 timertest[16576:c07] Timer fired
2013-01-23 23:54:12.483 timertest[16576:c07] Timer fired
2013-01-23 23:54:13.483 timertest[16576:c07] Timer fired
2013-01-23 23:54:14.483 timertest[16576:c07] Timer fired
2013-01-23 23:54:15.483 timertest[16576:c07] Timer fired
2013-01-23 23:54:15.484 timertest[16576:c07] ModelClass dealloc

关于iphone - 如何知道何时使 `NSTimer` 无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14490178/

相关文章:

ios - cellforrowatindexpath 混合单元格中的数据

ios - 如何从 Swift 调用 NSOperations 子类的 Obj C 自定义 Init 方法

objective-c - 使用@property(copy) 与@property(retain) 的经验法则是什么?

ios - UICollectionView 显示与所选单元格相关的图像

ios - 使用 NSURL 运行 swift 代码时出错 EXC_BAD_INSTRUCTION

ios - ScrollView 不会缩放

objective-c - 防止 bash 将 stdin 转发到 stderr

iphone - MonoTouch OpenGL 应用程序移动到后台时会丢失纹理数据

iphone - 如何在播放 MPMoviePlayerController 电影之前隐藏控件?

ios - 视网膜屏幕上的 GestureRecognizer