1.为什么会引起循环引用?

由于NSTimer会引用控制器self,而self又持有NSTimer对象,所以形成循环引用,在dealloc中停止定时器不会被执行的,Timer也永远不会被释放,这样也造成了内存泄漏。

2.如何解决?
 1.先说第一个比较麻烦的解决方法:

在viewwillappear方法中开启定时器,再在viewwilldisappear里面去关闭定时器。

-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    if (!self.timer) {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(showMsg) userInfo:nil repeats:YES];
    }
}

-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    if (self.timer) {
        [self.timer invalidate];
        self.timer = nil;
    }
}

这样虽然可以解决循环引用的问题,但是维护起来比较麻烦。

2.封装一个NStimer的category,提供block形式的接口:
#import <Foundation/Foundation.h>

@interface NSTimer (TimerBlock)

/**
 分类解决NSTimer在使用时造成的循环引用的问题

 @param interval 间隔时间
 @param block    回调
 @param repeats  用于设置定时器是否重复触发

 @return 返回NSTimer实体
 */
+ (NSTimer *)block_TimerWithTimeInterval:(NSTimeInterval)interval block:(void(^)())block repeats:(BOOL)repeats;

@end


#import "NSTimer+TimerBlock.h"

@implementation NSTimer (TimerBlock)
+ (NSTimer *)block_TimerWithTimeInterval:(NSTimeInterval)interval block:(void (^)())block repeats:(BOOL)reqeats{
    return [self timerWithTimeInterval:interval target:self selector:@selector(blockSelector:) userInfo:[block copy] repeats:reqeats];
}

+ (void) blockSelector:(NSTimer *)timer{
    void (^block)() = timer.userInfo;
    if (block) {
        block();
    }
}
@end

这个方式调用者是NStimer自己,这样我们在使用timer时,由于target的改变,就不再有循环引用的问题了。

3.给self添加中间件proxy:这个方法是利用runtime的消息转发机制来完成,后面会补充代码。