NSTimer作为自我定位的ivar

Mat*_*ing 5 objective-c nstimer

我遇到了一个尴尬的情况,我希望有一个带有NSTimer实例变量的类,只要该类处于活动状态,就会重复调用该类的方法.出于说明目的,它可能如下所示:

// .h
@interface MyClock : NSObject {
    NSTimer* _myTimer;
}
- (void)timerTick;
@end
Run Code Online (Sandbox Code Playgroud)

-

// .m
@implementation MyClock

- (id)init {
    self = [super init];
    if (self) {
        _myTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerTick) userInfo:nil repeats:NO] retain];
    }
    return self;
}

- (void)dealloc {
    [_myTimer invalidate];
    [_myTImer release];
    [super dealloc];
}

- (void)timerTick {
    // Do something fantastic.
}

@end
Run Code Online (Sandbox Code Playgroud)

这就是我想要的.我不想在我的类上公开一个接口来启动和停止内部计时器,我只是希望它在类存在时运行.看起来很简单.

但问题是NSTimer保留了目标.这意味着只要该计时器处于活动状态,它就会使该类不被正常的内存管理方法释放,因为计时器已保留它.手动调整保留计数是不可能的.NSTimer的这种行为似乎很难让重复计时器成为一个ivar,因为我无法想象一个ivar应该保留它自己的类的时间.

这让我有一种不愉快的责任,想出一些在MyClock上提供接口的方法,该方法允许类的用户控制定时器何时启动和停止.除了增加不必要的复杂性之外,这很烦人,因为让一个类的实例的一个所有者使计时器无效可以踩到另一个所有者的脚趾,该所有者指望它继续运行.我可以实现我自己的伪保留计数系统来保持计时器运行,但......严重吗?对于这样一个简单的概念,这是很有用的方法.

我能想到的任何解决方案都会让人感觉不舒服.我最终为NSTimer编写了一个包装器,其行为与普通的NSTimer完全相同,但不保留其目标.我不喜欢它,我很感激任何见解.

bbu*_*bum 4

由定时器引起的保留循环是一个令人头疼的问题。我使用过的最不脆弱的方法是不保留计时器,但在使其无效时始终将引用设置为 nil。

@interface Foo : NSObject
{
    __weak NSTimer *_timer;
}
@end

@implementation Foo
- (void) foo
{
    _timer = [NSTimer ....self....];
}

- (void) reset
{
    [_timer invalidate], _timer = nil;
}

- (void) dealloc
{
    // since the timer is retaining self, no point in invalidating here because
    // that just can't happen
    [super dealloc];
}
@end
Run Code Online (Sandbox Code Playgroud)

但最重要的是,你必须有一些东西-reset需要self发布。self解决方案是在和之间放置一个代理timer。代理可以有一个弱引用self,并简单地将计时器触发的调用传递给self。然后,当self被释放时(因为计时器不保留self,代理也不保留),您可以invalidate调用dealloc.

或者,如果针对 Mac OS X,请打开 GC 并完全忽略这些废话。