一步步学习ios

NSTimer的循环引用

2020-05-22  本文已影响0人  冷武橘

一、相互引用

- (void)viewDidLoad {
    [super viewDidLoad];
 self.timer = [NSTimer timerWithTimeInterval:1
 target:self selector:@selector(test2) userInfo:nil repeats:YES];
 [[NSRunLoop mainRunLoop]
addTimer:self.timer forMode: NSDefaultRunLoopMode];
}
- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
}

测试发现delloc不会被执行,很显然造成了相互引用。NStimer对象会对target对象(这里也就是控制器对象)进行强引用,而self.timer对象又被控制器对象引用,这样就会产生相互引用。

- (void)viewDidLoad {
    [super viewDidLoad];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"测试");
    }];
 [[NSRunLoop mainRunLoop]
addTimer:self.timer forMode: NSDefaultRunLoopMode];
}
- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
}

测试发现delloc会执行,不会出现相互引用。

- (void)viewDidLoad {
    [super viewDidLoad];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
         [self test2];
    }];
 [[NSRunLoop mainRunLoop]
addTimer:self.timer forMode: NSDefaultRunLoopMode];
}
- (void)test2{
     NSLog(@"动态进行");
}
- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
}

测试发现delloc不会被执行,同样造成了相互引用。当然很显然,这里是block引用了外部变量造成的。用关键字weak修饰就可以直接解决。

  __weak  typeof(self)weakself = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakself test2];
    }];

二、解决target的相互引用

- (void)viewDidLoad {
    [super viewDidLoad];
 self.timer = [NSTimer timerWithTimeInterval:1
 target:self selector:@selector(test2) userInfo:nil repeats:YES];
 [[NSRunLoop mainRunLoop]
addTimer:self.timer forMode: NSDefaultRunLoopMode];
}
- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
}

像block那样的套路,尝试使用weak修饰?不不不,weakself和self地址一样,并不会使NSTimer的target指针置弱。那怎样可行?答案是我们可以建立个自定义target对象,让NSTimer直接强引用它,自定义对象收到消息时转发回去,这样就可以巧妙的解决。

#import <UIKit/UIKit.h>
@interface TestProxy: NSObject
+ (instancetype)proxyWithTarget:(id)target;
@end

@interface TestProxy()
@property(nonatomic,weak)id target;
@end
@implementation TestProxy
+ (instancetype)proxyWithTarget:(id)target{
    TestProxy *proxy =  [[TestProxy alloc]init];
    proxy.target = target;
    return proxy;
}

//转发消息回去
- (id)forwardingTargetForSelector:(SEL)aSelector{
    return self.target;
}
@end


@implementation SecViewController
- (void)viewDidLoad {
    [super viewDidLoad];
     self.timer = [NSTimer timerWithTimeInterval:1 target:[TestProxy proxyWithTarget:self] selector:@selector(test2) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop]addTimer:self.timer forMode: NSDefaultRunLoopMode];
}
- (void)test2{
     NSLog(@"动态进行");
}
- (void)test{
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (void)dealloc{
    [self.timer invalidate];
    self.timer = nil;
}
@end

上一篇下一篇

猜你喜欢

热点阅读