Как получить уведомление, когда нулевая ссылка нуля равна нулю в Objective-C при ARC?

Существует ли механизм, позволяющий объекту знать, что нулевая слабая ссылка стала нулевой?

Например, у меня есть свойство

@property (nonatomic, weak) MyClass *theObject; 

когда theObject освобождается и свойство меняет нуль, я хочу получить уведомление. Но как? Использует ли эталонная система обнуления с помощью установщика значение свойства, равное нулю, когда объект уходит?

Время выполнения просто устанавливает слабый ivar _theObect равным нулю, пользовательский сеттер не вызывается.

Что вы могли бы сделать (если вам действительно нужно уведомление):

  • определить локальный класс «наблюдателя» и реализовать dealloc в этом классе,
  • создайте объект наблюдателя и установите его как «связанный объект» объекта _theObject.

Когда _theObject освобождается, связанный объект освобождается и освобождается (если нет других сильных рефериков к нему). Поэтому его метод dealloc вызывается. Это ваше «уведомление».

(Я пишу это по телефону и, если необходимо, позже может заполнить детали позже.)

Если вам интересно, когда объект уходит, вы не должны использовать слабую ссылку. Что ты пытаешься сделать?

Нет уведомления об освобождении объекта.

Система не будет использовать метод setter (это означает, что уведомления KVO не будут подняты). Ивар – истинная слабая ссылка, которая обнуляется. weak ключевое слово для свойства – это просто инструкция для синтеза ivar и публичное объявление о том, что объект не сохраняется.

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

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

Попробуйте это эмпирическое правило: будет ли программа работать корректно, если dealloc вообще не будет вызван? Если нет, вы должны пересмотреть логику программы, а не отправлять уведомления dealloc.

Я реализовал это, используя так называемый слабый реестр ссылок, см. Класс BMWeakReferenceRegistry , часть моей базы BMCommons с открытым исходным кодом для iOS.

Этот класс связывает объекты контекста с объектом интереса. Когда этот объект освобождается, так и объект контекста и вызывается блок очистки.

См. API:

 /** * Registry for monitoring the deallocation of objects of interest to perform cleanup logic once they are released. */ @interface BMWeakReferenceRegistry : BMCoreObject BM_DECLARE_DEFAULT_SINGLETON /** * Cleanup block definition */ typedef void(^BMWeakReferenceCleanupBlock)(void); /** * Registers a reference for monitoring with the supplied cleanup block. * The cleanup block gets called once the reference object gets deallocated. * * It is possible to register the same reference multiple times with different cleanup blocks (even if owner is the same). * If this is not intended behavior, check hasRegisteredReference:forOwner: before calling this method. * * @param reference The object to monitor * @param owner An optional owner (may be specified to selectively deregister references) * @param cleanup The cleanup block */ - (void)registerReference:(id)reference forOwner:(id)owner withCleanupBlock:(BMWeakReferenceCleanupBlock)cleanup; /** * Deregisters the specified reference for monitoring. If owner is not nil, only the monitor(s) for the specified owner is/are removed. * * @param reference The monitored reference * @param owner The optional owner of the reference */ - (void)deregisterReference:(id)reference forOwner:(id)owner; /** * Checks whether a monitor already exists for the specified reference/owner. If the owner parameter is nil all owners are checked. * * @param reference The monitored reference * @param owner The optional owner * @return True if registered, false otherwise. */ - (BOOL)hasRegisteredReference:(id)reference forOwner:(id)owner; @end 

нет системы уведомлений о слабых варах.

Ниже приведен пример, который я использовал для реализации многоадресной передачи делегатов. Возможно, было бы полезно проиллюстрировать, как контролировать «dealloc» слабых ссылочных объектов (делегатов).

Будет объект master DelegateRef. Его массив сохраняет записи всех делегатов, которые обертывают реальных делегатов. Основная цель здесь – удалить сильную ссылку на делегирование, сохраняемое массивом, когда действительные делегаты dealloc. Таким образом, создается локальный объект наблюдения и ассоциируется с делегатом при добавлении делегата. Когда локальные часы dealloc, делегатRef удаляется из массива master DelegateRef.

 #import <objc/runtime.h> @interface WeakWatcher : NSObject @property (nonatomic, weak) NSMutableArray *masterarray; @property (nonatomic, weak) DelegateRef *delegateRef; @end @implementation WeakWatcher -(void)dealloc { // when the object dealloc, this will be called if(_delegateRef != nil) { if([self.masterarray containsObject:_delegateRef]) { [_masterarray removeObject:_delegateRef]; } } } @end @interface DelegateRef() @end @implementation DelegateRef static char assoKey[] = "assoKey"; - (NSMutableArray *)array { if (_array == nil) { _array = [NSMutableArray array]; } return _array; } -(void)addWeakRef:(id)ref { if (ref == nil) { return; } DelegateRef *delRef = [DelegateRef new]; WeakWatcher* watcher = [WeakWatcher new]; // create local variable watcher.delegateRef = delRef; watcher.masterarray = self.array; [delRef setDelegateWeakReference:ref]; objc_setAssociatedObject(ref, assoKey, watcher, OBJC_ASSOCIATION_RETAIN); [self.array addObject:delRef]; } @end 
Interesting Posts
Давайте будем гением компьютера.