[NSTimer scheduledTimerWithTimeInterval:...]
方法会保留目标对象,所以如果目标对象是self,那么该模型类的实例将永远不会被释放。
解决方法是使用一个单独的对象(在下面的示例中称为TimerTarget
)。TimerTarget
对ModelClass
使用弱引用,以避免保留循环。
这个“辅助类”长这样。它的唯一目的是将定时器事件转发到“真正的目标”。
@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];
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
dealloc
已经很少使用了。我的属性在dealloc
方法中仍然有效吗? - Nosrettap