自我弱的 NSTimer;为什么不调用 dealloc?
NSTimer with weak self; why is dealloc not called?
考虑具有强(或弱,相同)的视图控制器NSTimer
属性:
__weak __typeof(self) ws = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:ws selector:@selector(timerTigger:) userInfo:nil repeats:YES];
但为什么这个视图控制器不调用 dealloc
方法,无论我通过 strong
还是 weak
引用 self
?
详细代码如下:
#import "SecondViewController.h"
@interface SecondViewController ()
@property (nonatomic, weak) NSTimer *timer;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
__weak __typeof(self) ws = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:ws selector:@selector(timerTigger:) userInfo:nil repeats:YES];
}
- (void)timerTigger:(id)timer {
NSLog(@"do someting");
}
- (void)dealloc {
NSLog(@"SecondViewController dealloc");
}
NSTimer
保持对其 target
的强引用,直到计时器失效。您无法选择 NSTimer
是建立弱参考还是强参考。当您传递弱引用时,只要在您启动计时器时 ws
不是 nil
(在这种情况下显然不会),NSTimer
将建立对 target
指出的任何内容的强烈引用。 scheduledTimerWithTimeInterval
是否建立强引用或弱引用不是您传递给它的指针的某些固有特征,而是该方法如何处理它所提供的指针的问题。
要修复这种强引用行为,您可以采用以下模式之一:
使用 NSTimer
的基于块的再现并在块内使用 "weak self" 模式;
@interface ViewController ()
@property (nonatomic, weak) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
typeof(self) __weak weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer) {
[weakSelf timerTigger];
}];
}
- (void)timerTigger {
NSLog(@"do something");
}
- (void)dealloc {
[self.timer invalidate];
}
@end
使用 GCD 计时器,它也是基于块的,因此也可以轻松配置为不保持强引用;或
@interface ViewController ()
@property (nonatomic, strong) dispatch_source_t timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
typeof(self) __weak weakSelf = self;
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
dispatch_source_set_event_handler(self.timer, ^{
[weakSelf timerTigger];
});
dispatch_resume(self.timer);
}
- (void)timerTigger {
NSLog(@"do something");
}
@end
将 NSTimer
与 target/selector 一起使用,但 invalidate
计时器在某个地方是合乎逻辑的(例如 viewDidDisappear
等)。
@interface ViewController ()
@property (nonatomic, weak) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerTigger:) userInfo:nil repeats:true];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.timer invalidate];
}
- (void)timerTigger:(NSTimer *)timer {
NSLog(@"do something");
}
@end
你可以试试这个:
@interface Person : NSObject
@property(nonatomic, strong) DemoViewController_19 *vc;
@end
@implementation Person
@end
@interface DemoViewController_19 ()
@property(nonatomic, strong) Person *person;
@end
@implementation DemoViewController_19
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.person = [Person new];
__weak typeof(self) weaks = self;
self.person.vc = weaks;
}
@end
在 运行 之后你可以看到 vc dealloc 没有被调用。取决于Person属性的强属性
考虑具有强(或弱,相同)的视图控制器NSTimer
属性:
__weak __typeof(self) ws = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:ws selector:@selector(timerTigger:) userInfo:nil repeats:YES];
但为什么这个视图控制器不调用 dealloc
方法,无论我通过 strong
还是 weak
引用 self
?
详细代码如下:
#import "SecondViewController.h"
@interface SecondViewController ()
@property (nonatomic, weak) NSTimer *timer;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
__weak __typeof(self) ws = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:ws selector:@selector(timerTigger:) userInfo:nil repeats:YES];
}
- (void)timerTigger:(id)timer {
NSLog(@"do someting");
}
- (void)dealloc {
NSLog(@"SecondViewController dealloc");
}
NSTimer
保持对其 target
的强引用,直到计时器失效。您无法选择 NSTimer
是建立弱参考还是强参考。当您传递弱引用时,只要在您启动计时器时 ws
不是 nil
(在这种情况下显然不会),NSTimer
将建立对 target
指出的任何内容的强烈引用。 scheduledTimerWithTimeInterval
是否建立强引用或弱引用不是您传递给它的指针的某些固有特征,而是该方法如何处理它所提供的指针的问题。
要修复这种强引用行为,您可以采用以下模式之一:
使用
NSTimer
的基于块的再现并在块内使用 "weak self" 模式;@interface ViewController () @property (nonatomic, weak) NSTimer *timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; typeof(self) __weak weakSelf = self; self.timer = [NSTimer scheduledTimerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer) { [weakSelf timerTigger]; }]; } - (void)timerTigger { NSLog(@"do something"); } - (void)dealloc { [self.timer invalidate]; } @end
使用 GCD 计时器,它也是基于块的,因此也可以轻松配置为不保持强引用;或
@interface ViewController () @property (nonatomic, strong) dispatch_source_t timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; typeof(self) __weak weakSelf = self; self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC); dispatch_source_set_event_handler(self.timer, ^{ [weakSelf timerTigger]; }); dispatch_resume(self.timer); } - (void)timerTigger { NSLog(@"do something"); } @end
将
NSTimer
与 target/selector 一起使用,但invalidate
计时器在某个地方是合乎逻辑的(例如viewDidDisappear
等)。@interface ViewController () @property (nonatomic, weak) NSTimer *timer; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerTigger:) userInfo:nil repeats:true]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [self.timer invalidate]; } - (void)timerTigger:(NSTimer *)timer { NSLog(@"do something"); } @end
你可以试试这个:
@interface Person : NSObject
@property(nonatomic, strong) DemoViewController_19 *vc;
@end
@implementation Person
@end
@interface DemoViewController_19 ()
@property(nonatomic, strong) Person *person;
@end
@implementation DemoViewController_19
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.person = [Person new];
__weak typeof(self) weaks = self;
self.person.vc = weaks;
}
@end
在 运行 之后你可以看到 vc dealloc 没有被调用。取决于Person属性的强属性