NSTimer自我弱; 为什么没有叫dealloc?

hua*_*nyu 2 objective-c nstimer dealloc ios

考虑具有强(或弱,相同)NSTimer属性的视图控制器:

__weak __typeof(self) ws = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:ws selector:@selector(timerTigger:) userInfo:nil repeats:YES];
Run Code Online (Sandbox Code Playgroud)

但是为什么这个视图控制器不会调用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");
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 11

NSTimer保持对它的强引用,target直到计时器失效.您无法选择是NSTimer建立弱引用还是强引用.当你传递一个弱引用时,只要ws不是nil你启动计时器的时间(在这种情况下很明显不会),NSTimer就会建立对指向的任何target指针的强引用.是否scheduledTimerWithTimeInterval建立一个强引用或弱引用并不是你传递给它的指针的一些固有特性,而是一个问题,即该方法对它所提供的指针的作用.

要修复此强引用行为,您可以采用以下模式之一:

  • 使用基于块的再现NSTimer并在块内使用"弱自我"模式;

    @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
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用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
    
    Run Code Online (Sandbox Code Playgroud)
  • 使用NSTimer与目标/选择器,但是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
    
    Run Code Online (Sandbox Code Playgroud)