造成内存泄漏&循环引用的原因
- 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 <Foundation/Foundation.h>
@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对象。