NSTimer

造成内存泄漏&循环引用的原因

  • self->timer->self
  • runloop->timer->self

解决 NSTimer 循环引用

// 方式一 
__weak __typeof(self)weakSelf = self;
_blockTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
    __weak __typeof(weakSelf)strongSelf = weakSelf;
    NSLog(@"%@", strongSelf);
}];
[_blockTimer fire];

// 方式二
_normalTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:[YYWeakProxy proxyWithTarget:self] selector:@selector(nTimer) userInfo:nil repeats:YES];
[_normalTimer fire];

这两种方式都需要在 dealloc 中:

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

YYWeakProxy 的实现

#import 

@interface YYWeakProxy : NSProxy
@property (nonatomic, weak, readonly) id target;
- (instancetype)initWithTarget:(id)target;
+ (instancetype)proxyWithTarget:(id)target;
@end
#import "YYWeakProxy.h"

@implementation YYWeakProxy

- (instancetype)initWithTarget:(id)target {
    _target = target;
    return self;
}
+ (instancetype)proxyWithTarget:(id)target {
    return [[YYWeakProxy alloc] initWithTarget:target];
}
- (id)forwardingTargetForSelector:(SEL)selector {
    return _target;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
    void *null = NULL;
    [invocation setReturnValue:&null];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
    return [NSObject instanceMethodSignatureForSelector:@selector(init)];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
    return [_target respondsToSelector:aSelector];
}
- (BOOL)isEqual:(id)object {
    return [_target isEqual:object];
}
- (NSUInteger)hash {
    return [_target hash];
}
- (Class)superclass {
    return [_target superclass];
}
- (Class)class {
    return [_target class];
}
- (BOOL)isKindOfClass:(Class)aClass {
    return [_target isKindOfClass:aClass];
}
- (BOOL)isMemberOfClass:(Class)aClass {
    return [_target isMemberOfClass:aClass];
}
- (BOOL)conformsToProtocol:(Protocol *)aProtocol {
    return [_target conformsToProtocol:aProtocol];
}
- (BOOL)isProxy {
    return YES;
}
- (NSString *)description {
    return [_target description];
}
- (NSString *)debugDescription {
    return [_target debugDescription];
}
@end

为什么方式二通过NSProxy,而不能通过 weakSelf 解决

runloop->timer->weakSelf->self

/var/folders/27/wz97zmvn6fx_pw_kzbbrrm580000gn/T/BViewController-32f70f.mi:60696:20: error: 
cannot create __weak reference because the current deployment target does not support weak references
__attribute__((objc_ownership(weak))) typeof(self) weakself = self;

weak指针指向对象指针,顺着这条路,target依然可以强引用NSTimer对象。

你可能感兴趣的:(NSTimer)