在后台线程中使用时,NSTimer导致内存泄漏


- (void)addTimer {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
__strong typeof(self) strongSelf = weakSelf;
strongSelf.timer = [NSTimer scheduledTimerWithTimeInterval:20 repeats:YES block:^(NSTimer * _Nonnull timer) {

}];
NSRunLoop *currentLoop = [NSRunLoop currentRunLoop];
[currentLoop addTimer:strongSelf.timer forMode:NSRunLoopCommonModes];
[currentLoop run];

});
}

为什么这种代码会导致内存泄漏?当我删除__strong typeof(self) strongSelf = weakSelf;时,它工作正常。我应该添加__strong typeof(self) strongSelf = weakSelf;吗?

NSTimer处理同一问题的方法完全不同。你想要一个自由运行的非中断定时器,它每20秒就会启动一次,即使目标被释放,也不应该泄漏。这是NSProxy非常方便地发挥作用的情况之一。这只是三行代码,但很安全。

假设你有一个CCD_ 5;updateMethod";你想传递调用。

@interface YourTargetObject : NSObject
-(void)updateMethod;
@end

NSProxy看起来像。

@interface YourWeakDelegateProxy : NSProxy
-(instancetype)initWithTarget:(YourTargetObject*)target;
@property (nonatomic, weak) YourTargetObjectClass * target;
@end

详细的调用。我们只在这里传递一个委托指针,并将调用转发到选择器。

@implementation YourWeakDelegateProxy
-(instancetype)initWithTarget:(YourTargetObject*)target {
self.target = target;
return self;
}
-(NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
-(void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:_target];
[invocation invoke];
}
@end

现在,您可以使用类中某个位置的计时器以以下方式调用一个(可能以后不再存在)对象。。

self.timer = [NSTimer 
scheduledTimerWithTimeInterval:20.0 
target:[[YourWeakDelegateProxy alloc] initWithTarget:self]
selector:@selector(updateMethod) 
userInfo:nil 
repeats:NO];

并且像往常一样密切关注定时器的释放
实际上ARC是为你做的。。但看起来还是。。

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

因此,现在可以保证计时器在新的代理上调用
代理转发对委托的调用。如果代理(自身)在您的20秒内无效,则不会发生任何不良情况。

附言:提醒。。每个线程至少有一个运行循环,但并不是每个运行循环都有自己的线程,相反,它们有时共享一个线程。

- (void)addTimer {
__weak __typeof(self)weakSelf = self;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
weakSelf.timer = [NSTimer scheduledTimerWithTimeInterval:20 repeats:YES block:^(NSTimer * _Nonnull timer) {
}];
NSRunLoop *currentLoop = [NSRunLoop currentRunLoop];
[currentLoop addTimer:weakSelf.timer forMode:NSRunLoopCommonModes];
[currentLoop run];
});
}

此代码将起作用。在块中,您需要一个对象的弱引用。如果你在一个区块内占领了一个物体的据点,那么ARC将无法释放其内存。

最新更新