Управление памятью NSTimer

Когда я выполняю этот код:

[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO];

Нужно ли это использовать или освободить его, независимо от управления памятью?

Я использую ARC

Ответ 1

Да, NSTimer будет поддерживать сильную ссылку на target, что может привести к сильным опорным циклам (особенно в повторяющихся таймерах) (циклы сохранения a.k.a.). В вашем примере, тем не менее, таймер не повторяется и задерживается только на 0,5, поэтому в худшем случае у вас будет сильный опорный цикл, который автоматически разрешит себя через 0,5 секунды.

Но общий пример нерешенного сильного опорного цикла будет иметь UIViewController со свойством NSTimer, который повторяется, но потому, что NSTimer имеет сильную ссылку на UIViewController, контроллер закончится сохраняются.

Итак, если вы сохраняете NSTimer как переменную экземпляра, то да, вы должны invalidate it, чтобы решить сильный ссылочный цикл. Если вы просто вызываете scheduledTimerWithTimeInterval, но не сохраняете его в переменной экземпляра (как можно было бы сделать вывод из вашего примера), тогда ваш сильный ссылочный цикл будет разрешен, когда NSTimer будет завершен.

И, кстати, если вы имеете дело с повторением NSTimers, не пытайтесь invalidate их в dealloc владельца NSTimer, потому что dealloc явно не будет до тех пор, пока не будет разрешен сильный опорный цикл. Например, в случае UIViewController вы можете сделать это в viewDidDisappear.

Кстати, Руководство по программированию памяти с расширенным управлением объясняет, каковы сильные ссылочные циклы. Ясно, что это в разделе, где они описывают правильное использование слабых ссылок, что здесь неприменимо (потому что вы не контролируете тот факт, что NSTimer использует сильные ссылки на цель), но он объясняет концепции сильных эталонных циклов приятно.


Если вы не хотите, чтобы NSTimer сохранял сильную ссылку на self, в macOS 10.12 и iOS 10 или более поздней версии вы можете использовать исполнение блока, а затем использовать шаблон weakSelf:

typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:0.5 repeats:false block:^(NSTimer * _Nonnull timer) {
    [weakSelf showButtons];
}];

Кстати, я замечаю, что вы вызываете showButtons. Если вы пытаетесь просто показать некоторые элементы управления в своем представлении, вы можете полностью исключить использование NSTimer и сделать что-то вроде:

self.button1.alpha = 0.0;
self.button2.alpha = 0.0;

[UIView animateWithDuration:0.25
                      delay:0.5
                    options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                 animations:^{
                     self.button1.alpha = 1.0;
                     self.button2.alpha = 1.0;
                 }
                 completion:nil];

Это не вызывает проблем с сохранением объектов NSTimer и выполняет как задержку, так и грациозное отображение кнопки (ов) в одном выражении. Если вы выполняете дополнительную обработку в своем методе showButtons, вы можете поместить это в блок completion.

Ответ 2

Если вы сохраняете его в свойстве, то да, вам нужно установить его на нуль после его запуска.

Также безопасно сохранять его, если ваш класс будет освобожден по какой-либо причине, так что вы можете [timer invalidate], если вам нужно.

Ответ 3

Да, вы можете использовать: myTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO]; И затем в вашем представленииDidDisappear [myTimer invalidate]

Ответ 4

Используйте новый метод Timer, который использует замыкания

timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: {[weak self] (timer) in
   print("Tick tock")
   guard let ws = self else { return }
   //some action that repeats
   ws.myViewControllerMethod()
})