NSTimer相信大家經(jīng)常都會(huì)用到,但是,如果不注意的話,很容易就會(huì)造成內(nèi)存泄漏。
我們先來暫時(shí)一個(gè)例子:
@interface HomeControllerViewController ()
@property(nonatomic, strong)NSTimer *timer;
@end
@implementation HomeControllerViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor redColor];
self.timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timerSchedue:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- (void)timerSchedue:(NSTimer *)timer {
static int i = 0;
NSLog(@"%d",i);
i++;
}
- (void)dealloc {
NSLog(@"已經(jīng)銷毀HomeControllerViewController");
}
@end
如果你從A controller推進(jìn)一個(gè)Homecontroller,然后再點(diǎn)返回,那么造成的現(xiàn)象就是,一直打印1,2,3......不會(huì)停止,直到你殺掉進(jìn)程。并且,NSLog(@"已經(jīng)銷毀HomeControllerViewController");這句不會(huì)打印。
原因分析
為什么會(huì)這樣呢?
可能有人會(huì)猜:既然不走delloc方法,那肯定就是有循環(huán)引用在,導(dǎo)致不能釋放HomeControllerViewController,那么,我把timer的target傳weakSelf,會(huì)不會(huì)解決這個(gè)問題呢?
經(jīng)過試驗(yàn)之后,答案是,并不能,還是不走delloc方法。
那么,我們要怎么解決這個(gè)問題呢?
我們先來看看文檔:

文檔上有提到,The receiver retains a Timer。很明顯,接收者會(huì)強(qiáng)引用timer,那么你穿weakSelf就沒什么用了。

如果我們采取一個(gè)proxy類,把他的引用斷開呢?

這樣是否可以解決這個(gè)問題呢?按原理來說是應(yīng)該可以的。我們來嘗試下:
我們先創(chuàng)建一個(gè)weakProxy類:
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface WeakProxy : NSProxy
@property (weak,nonatomic,readonly)id target;
+ (instancetype)proxyWithTarget:(id)target;
- (instancetype)initWithTarget:(id)target;
@end
NS_ASSUME_NONNULL_END
#import "WeakProxy.h"
@implementation WeakProxy
- (instancetype)initWithTarget:(id)target {
_target = target;
return self;
}
+ (instancetype)proxyWithTarget:(id)target {
return [[WeakProxy 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
這個(gè)時(shí)候,我們的timer的target要改一下,改成weakproxy:
self.timer = [NSTimer timerWithTimeInterval:1 target:[WeakProxy proxyWithTarget:self] selector:@selector(timerSchedue:) userInfo:nil repeats:YES];
我們運(yùn)行來看看效果:

果然,delloc的方法執(zhí)行了,說明,循環(huán)引用被打破了。
所以,后面如果用到NSTimer的時(shí)候,記得要注意這個(gè)問題哦.....