iOS - NSTimer中 Target 的 Self 强引用

2022-05-27  本文已影响0人  一滴矿泉水

一、 问题原因

截屏2022-05-27 下午4.41.20.png
#import "OneiewController.h"

@interface OneiewController ()
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation OneiewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    [self dismissViewControllerAnimated:YES completion:nil];
}

-(void)viewDidLoad{

    [super viewDidLoad];
    //开启定时器
    self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(testTimerDealloc) userInfo:nil repeats:YES];

}
/** 方法一直执行 */
-(void)testTimerDealloc{

    NSLog(@"-----");
}
/** 开启定时器以后控制器不能被销毁,此方法不会被调用 */
-(void)dealloc{
     NSLog(@"xiaohui");
    [self.timer invalidate];

}
@end

二、 解决办法

@interface TimerWeakTarget : NSObject

@property (nonatomic, assign) SEL selector;

@property (nonatomic, weak) NSTimer *timer;

@property (nonatomic, weak) id target;
/**
 1.重写开启定时器方法,在内部对target进行替换,换成本类(TimerWeakTarget)的对象即可
 2.不会造成循环引用了,原控制器OneViewController属性有timer对timer强应用,timer内部对self强引用,但是self在此方法内部被替换成了本类的对象(TimerWeakTarget *),而本类的对象不会对OneViewController强引用,则不会造成循环引用,也就不会造成内存泄露
 */
+ (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                  target:(id)aTarget
                                selector:(SEL)aSelector
                                userInfo:(id)userInfo
                                 repeats:(BOOL)repeats;

@end
#import "TimerWeakTarget.h"

@implementation TimerWeakTarget
+ (NSTimer *) scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                  target:(id)aTarget
                                selector:(SEL)aSelector
                                userInfo:(id)userInfo
                                 repeats:(BOOL)repeats{

    TimerWeakTarget * timer = [TimerWeakTarget new];
    timer.target = aTarget;
    timer.selector = aSelector;
//-------------------------------------------------------------此处的target已经被换掉了不是原来的VIewController而是TimerWeakTarget类的对象timer
timer.timer = [NSTimer scheduledTimerWithTimeInterval:interval target:timer selector:@selector(fire:) userInfo:userInfo repeats:repeats];
return timer.timer;
}

-(void)fire:(NSTimer *)timer{

    if (self.target) {
        [self.target performSelector:self.selector withObject:timer.userInfo];
    
    } else {

        [self.timer invalidate];
    }
}


@end
#import "OneiewController.h"
#import "TimerWeakTarget.h"

@interface OneiewController ()
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation OneiewController

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    [self dismissViewControllerAnimated:YES completion:nil];
}

-(void)viewDidLoad{

    [super viewDidLoad];
    //开启定时器
    self.timer = [TimerWeakTarget scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(testTimerDealloc) userInfo:nil repeats:YES];

}
/** 方法一直执行 */
-(void)testTimerDealloc{

    NSLog(@"-----");
}
/** 开启定时器以后控制器不能被销毁,此方法不会被调用 */
-(void)dealloc{
    NSLog(@"xiaohui");
    [self.timer invalidate];

}

@end

文章持续更新中、希望对各位有所帮助、有问题可留言 大家共同学习.

上一篇 下一篇

猜你喜欢

热点阅读