NSTimer retainCount не равен нулю после аннулирования - PullRequest
0 голосов
/ 09 мая 2018

Я провёл тест и запутался с результатом.

NSTimer  *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));

[timer invalidate];

NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));

И результат:

2018-05-09 21: 57: 35.708544 + 0800 newtest [539: 96880] Счетчик сохранения таймера равен 3

2018-05-09 21: 57: 40.104955 + 0800 newtest [539: 96880] Счетчик сохранения таймера равен 2

почему NSTimer retainCount не равен нулю после аннулирования?

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Объяснение Роба верно.

Я просто добавил еще несколько деталей, чтобы доказать, что вызов scheduledTimerWithTimeInterval:target:selector:userInfo:repeats возвращает объект autorelase 100

В XCode вы можете использовать Product-> Perform Action -> Assemble для просмотра кода сборки

bl  _objc_msgSend
mov  x29, x29   ;
bl  _objc_retainAutoreleasedReturnValue; Here you see that the return value is Autoreleased

Итак, до invalid:

  • автоотключение => + 1
  • runloop => + 1
  • сохранить => + 1

Результат 3

После invalid

  • автоотключение => + 1
  • сохранить => + 1

Результат 2

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

0 голосов
/ 09 мая 2018

На самом деле не ваше дело знать, почему счет сохранения не равен нулю. Сохраняемые значения - это детали реализации, и лучше не обращать на них внимания, если вы можете этого избежать.

Вот что говорит документация invalidate:

Объект NSRunLoop удаляет свою сильную ссылку на таймер либо непосредственно перед возвратом метода invalidate, либо в какой-то более поздний момент.

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

Кроме того, невозможно когда-либо увидеть, чтобы количество сохраняемых объектов было равно нулю. Когда счет удержания станет равным нулю, объект уничтожается вместо этого, и вы не можете воздействовать (например, на вызов CFGetRetainCount) на уничтоженный объект. Память объекта, вероятно, была перезаписана, поэтому попытка что-либо сделать с ним - неопределенное поведение.

Тем не менее, мы можем сделать некоторые предположения о том, почему счет удержания по-прежнему равен 2 после invalidate.

Во-первых, мы знаем, что ваша локальная переменная timer имеет сильную ссылку на таймер, поэтому на счетчик сохраняется +1.

Селектор scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: не начинается с new или alloc или copy, поэтому он, вероятно, автоматически освобождает объект. Это, вероятно, другой +1 в счет удержания; объект, вероятно, находится в пуле автоматического выпуска. Подробнее см. Руководство по программированию для расширенного управления памятью .

Вы можете проверить теорию автоматического выпуска следующим образом:

NSTimer *timer;
@autoreleasepool {
    timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
    NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));

    [timer invalidate];
    NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));
}

NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));
// If the retain count is now 1, the timer was in the autoreleasepool,
// and the local `timer` variable now has the only strong reference to
// the timer.
...