- (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将无法释放其内存。