iOS NSTimer之循环引用

1、计时器创建

1)第一种 默认直接开启

//NSTimer第一种写法
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(runTimerMethed) userInfo:nil repeats:YES];

2)第二种

@property (nonatomic,strong)NSTimer *timer;

//NSTimer第二种写法
self.timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(runTimerMethed) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
- (void)runTimerMethed{
    NSLog(@"计时器走了--");
}

- (void)dealloc{
    NSLog(@"dealloc");
  
    [self.timer invalidate];
    self.timer = nil;
}

2、下面进行操作

当前页面为vc1,前一个页面为vc,后一个页面为vc2
1、从vc进入vc1,计时器方法开始执行,pop回vc,计时器还在跑,dealloc方法不会执行

原因:timer被runloop持有,timer释放不掉,timer又持有self,所以导致self释放不掉。不会走dealloc方法。

循环引用关系图

那就想办法~~~

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

从vc1pop回vc,可以正常dealloc了
but
从vc1进入vc2,计时器停掉了,再返回vc1,计时器开始跑,不准,pass掉该方法

3、解决方案

1)第一种:

//添加、移除进navi里执行该方法  parent = UINavigationController
- (void)didMoveToParentViewController:(UIViewController *)parent{
    if (parent == nil) {
        [self.timer invalidate];
        self.timer = nil;
    }
}

2)第二种:中间对象

原理图:


target原理图
@property (nonatomic,strong)NSObject *target;
_target = [[NSObject alloc]init];
class_addMethod([_target class], @selector(runTimerMethed), (IMP)runMethedIMP, "v@:");
self.timer = [NSTimer timerWithTimeInterval:1.0f target:_target selector:@selector(runTimerMethed) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
void runMethedIMP(id self,SEL _cmd){
    NSLog(@"IMP计时器走了--");
}
- (void)dealloc{
    NSLog(@"dealloc");
    [self.timer invalidate];
    self.timer = nil;
}

3)第二种:NSProxy

橙色箭头:强引用
绿色箭头:弱引用


NSProxy原理图示
@interface HHProxy : NSProxy

@property (weak,nonatomic)id target;

@end
#import "HHProxy.h"

@implementation HHProxy

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
    return [_target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation{
    [invocation invokeWithTarget:_target];
}
@end

调用:

_proxy = [HHProxy alloc];
_proxy.target = self;
self.timer = [NSTimer timerWithTimeInterval:1.0f target:_proxy selector:@selector(runTimerMethed) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容