2016-01-07 1 views
1

У меня есть одноэлементный класс в моем приложении, который создается при запуске приложения и всегда используется. Теперь я собираюсь ввести NSTimer, который периодически вызывает один из методов singleton, поэтому я понимаю, что таймер сохранит сильную ссылку на мой одноэлементный класс (поскольку одноэлементный класс является целью). Это верно? Что еще более важно, это сильный цикл сохранения проблемы для одного класса, который должен жить в течение всего времени приложения? Если да, то почему?Является ли сильный цикл сохранения релевантным соображением для одного класса, который должен существовать для жизни приложения?

+2

Тот факт, что вы имеете дело с синглом, должен быть неактуальным. Используйте надлежащее управление памятью независимо от того, что. – rmaddy

+1

Где, по вашему мнению, есть цикл удержания? Имеет ли синглтон ссылку на таймер? –

+0

Если ваш синглтон создает повторяющийся таймер, который вызывает метод вашего синглтона, а singleton поддерживает сильную ссылку на таймер, то да, у вас есть цикл сохранения. Тем не менее, это действительно только академическая проблема, так как ваш синглтон сохраняется для жизни вашего приложения. Сохранять циклы являются плохими, если они заставляют объекты сохраняться в памяти после того, как все другие ссылки на них будут выпущены. –

ответ

1

Я считаю, что это проблема. Одиночный класс уже сложно реорганизовать и повторно использовать. Добавление цикла сохранения в один приведет к тому, что класс, который намного сложнее изменить или повторно использовать в будущем. Когда вы обнаружите, что вам нужен этот класс (или, по крайней мере, набор обязанностей, на который этот таймер является частью), чтобы не быть синглом, вам также нужно запомнить или идентифицировать эту утечку памяти и исправить ее как часть вашего рефактора. Будущее, вероятно, будет печальным.

Вместо этого вы можете написать класс, который следует за хорошими шаблонами (для управления памятью и т. Д.) Независимо от того, доступен ли он как одноэлементный или нет. В вашем случае это может означать сохранение слабой ссылки на таймер («Note in particular that run loops maintain strong references to their timers, so you don’t have to maintain your own strong reference to a timer after you have added it to a run loop.») и аннулирование этого таймера, если этот объект освобожден.

1

Вы спрашиваете:

У меня есть одноэлементный класс в моем приложении, которое создается при запуске приложения и всегда в использовании. Теперь я собираюсь ввести NSTimer, который периодически вызывает один из методов singleton, поэтому я понимаю, что таймер сохранит сильную ссылку на мой одноэлементный класс (поскольку одноэлементный класс является целью). Это верно?

Да, NSTimer будет поддерживать сильную ссылку на этот экземпляр класса singleton. Эта сильная ссылка сохраняется до тех пор, пока вы не станете таймером (или в случае не повторяющегося таймера, пока не загорится таймер).

Что еще более важно, это сильный цикл сохранения проблемы для одноэлементного класса, который должен жить в течение всего времени приложения? Если да, то почему?

Тот факт, что запланированный экземпляр NSTimer поддерживает сильную ссылку на цель его обработчика, само по себе не является проблемой. Вы просто должны знать об этом факте и управлять своей памятью соответствующим образом. Все это означает, что если вы закончили с каким-либо объектом, который является объектом NSTimer, вы несете ответственность за ручное вызов invalidate этого таймера.

Единственный момент, когда эта сильная ссылка на обработчик таймера становится проблематичной, - это когда вы имеете дело с каким-либо объектом, который имеет более временный характер (например, контроллер вида, который позже может быть отклонен). Слишком часто люди думают: «О, я просто invalidate, что NSTimer в методе dealloc», но это не работает. Метод Objective-C dealloc (а также метод Swift deinit) не вызывается до тех пор, пока не будет более сильных ссылок, поэтому вы не можете попытаться устранить сильную ссылку этого таймера в dealloc, потому что dealloc не может быть вызван до тех пор, пока таймер недействителен. Вместо этого, если вы закончили с целью NSTimer, вы должны вручную указать таймер (например, в случае примера контроллера просмотра люди часто делают это в viewDidDisappear).

В вашем случае тот факт, что у вас есть запланированный повторяющийся таймер, вызывающий метод singleton, не является проблемой. Просто имейте в виду, что этот одноэлементный объект (который, скорее всего, никогда не выпадет из области видимости), не может быть освобожден до тех пор, пока запланированный NSTimer все еще активен. Вам нужно будет invalidateNSTimer, чтобы устранить сильную ссылку на эту цель.


Два дополнительных наблюдений:

  1. Вы описали это NSTimer поведение в качестве сильного опорного цикла (цикл удержания). Технически это не сильный ссылочный цикл, а скорее факт, что график NSTimer сохраняется в цикле выполнения, на котором он запланирован, а затем таймер сохраняет цель, на которую запланирован ее обработчик.

    Это несколько академическое различие (потому что оно проявляет себя подобно сильному эталонному циклу), но это стоит отметить.

  2. Вы также должны знать, что вместо использования NSTimer вы также можете использовать таймер источника отправки GCD. Таким образом, создать свойство таймера в классе:

    @property (nonatomic, strong) dispatch_source_t timer; 
    

    А затем создать экземпляр и запустить таймер:

    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); 
    dispatch_source_set_event_handler(self.timer, ^{ 
        [weakSelf handleTimer]; 
    }); 
    dispatch_resume(self.timer); 
    

    Эта модель, в отличие от NSTimer подхода, не сохраняет цель таймера (или , в этом случае объект, по которому мы ссылаемся через self) из-за использования шаблона weakSelf в блоке (который разрешает любой сильный опорный цикл). Таким образом, мы в конечном итоге в таймере, который безопасно выпущен, когда объект, который содержит это освобождаться, без сильного опорного цикла.

0

Сохранять цикл не может быть проблематичным в это время, как вы используете одноплодной, который не нуждается в открепление, но что, если в будущем кто-то еще refactors одноэлементных в обычный класс?

Другое соображение состоит в том, что NSTimer не очень энергоэффективны, и Apple warmly recommends переключается на GCD источники для выполнения задач, связанных с таймером. Возможно, вы даже сможете сломать цикл сохранения через ссылки weak с этим подходом.

Смежные вопросы