文章以在TimerViewController中使用計時器為例,在VC中聲明一個NSTimer屬性。
創(chuàng)建NSTimer對象:
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(startTimer) userInfo:nil repeats:YES];
timer作為VC的屬性,被VC強引用,創(chuàng)建timer對象時VC作為target被timer強引用,即循環(huán)引用。

解決循環(huán)引用的幾種方式:
weak指針:
既然是強引用導(dǎo)致循環(huán)引用,那么用__weak修飾self就好了,想法是對的,但是做法是無效的。因為無論是weak還是strong修飾,在NSTimer中都會重新生成一個新的強引用指針指向self,導(dǎo)致循環(huán)引用的。
類方法:
創(chuàng)建一個繼承NSObject的子類TempTarget,并創(chuàng)建開啟計時器的方法。
TempTarget .h文件
@property (nonatomic, assign) SEL selector;
@property (nonatomic, weak) NSTimer *tempTimer;
@property (nonatomic, weak) id tempTarget;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval target:(id)tempTarget selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)repeats;
TempTarget .m文件
@implementation TempTarget
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval target:(id)tempTarget selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)repeats {
TempTarget *target = [[TempTarget alloc] init];
target.tempTarget = tempTarget;
target.selector = selector;
target.tempTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:target selector:@selector(timerSelector:) userInfo:userInfo repeats:repeats];
return target.tempTimer;
}
- (void)timerSelector:(NSTimer *)tempTimer {
if (self.tempTarget && [self.tempTarget respondsToSelector:self.selector]) {
[self.tempTarget performSelector:self.selector withObject:tempTimer.userInfo];
}else {
[self.tempTimer invalidate];
}
}
@end
VC調(diào)用
self.timer = [TempTarget scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerStart:) userInfo:nil repeats:YES];
VC強引用timer,因為timer的target是TempTarget實例,所以timer強引用TempTarget實例,而TempTarget實例弱引用VC,解除循環(huán)引用。

WeakProxy:
創(chuàng)建一個繼承NSProxy的子類WeakProxy,并實現(xiàn)消息轉(zhuǎn)發(fā)的相關(guān)方法。
WeakProxy.h文件
@property (nonatomic, weak, readonly) id weakTarget;
+ (instancetype)proxyWithTarget:(id)target;
- (instancetype)initWithTarget:(id)target;
WeakProxy.m文件
@implementation WeakProxy
+ (instancetype)proxyWithTarget:(id)target {
return [[self alloc] initWithTarget:target];
}
- (instancetype)initWithTarget:(id)target {
_weakTarget = target;
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL sel = [invocation selector];
if ([self.weakTarget respondsToSelector:sel]) {
[invocation invokeWithTarget:self.weakTarget];
}
}
//返回方法的簽名。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.weakTarget methodSignatureForSelector:sel];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
return [self.weakTarget respondsToSelector:aSelector];
}
@end
VC調(diào)用
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[WeakProxy proxyWithTarget:self] selector:@selector(timerStart:) userInfo:nil repeats:YES];
- (void)dealloc {
[_timer invalidate];
NSLog(@"VC銷毀了");
}
原理跟類方法相似,打破循環(huán)引用的環(huán)路。將timer的target設(shè)置為WeakProxy實例,利用消息轉(zhuǎn)發(fā)機制實現(xiàn)執(zhí)行VC中的計時方法,解決循環(huán)引用。
GCD:
VC的.m文件
@interface ViewController ()
@property (nonatomic, strong) dispatch_source_t timer;
@end
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
dispatch_source_set_timer(_timer, dispatch_time(DISPATCH_TIME_NOW, 0), 0.1*NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_timer, ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"執(zhí)行了");
});
});
//開啟計時器
dispatch_resume(_timer);
}
//結(jié)束計時
dispatch_source_cancel(_timer);
Block:
創(chuàng)建NSTimer的分類NSTimer+UnretainCycle。
+ (NSTimer *)lhScheduledTimerWithTimeInterval:(NSTimeInterval)inerval
repeats:(BOOL)repeats
block:(void(^)(NSTimer *timer))block {
return [NSTimer scheduledTimerWithTimeInterval:inerval target:self selector:@selector(blcokInvoke:) userInfo:[block copy] repeats:repeats];
}
+ (void)blcokInvoke:(NSTimer *)timer {
void (^block)(NSTimer *timer) = timer.userInfo;
if (block) {
block(timer);
}
}
VC調(diào)用
self.timer = [NSTimer mxScheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer *timer) {
NSLog(@"執(zhí)行了");
}];