Objective C блокирует как асинхронные обратные вызовы и плохой доступ - PullRequest
9 голосов
/ 30 июля 2011

У меня есть серьезные сомнения.Предположим, следующий сценарий:

  1. У вас есть UIViewController на экране.
  2. Приложение инициирует, скажем, внутренний вызов, используя блок в качестве обратного вызова
  3. Выиспользуйте суррогат 'self', чтобы предотвратить сохранение циклов.
  4. Пользователь нажимает 'Back', и UIViewController получает освобождение '.
  5. Рано или поздно блок обратного вызова выполняется>> BAD ACCESS

До выхода iOS 4 мы имели дело с подобной ситуацией, установив nil свойство delegate для ... я не знаю, каким классом вы былииспользуя.

Но в наше время ... как вы отменяете блок ??.Что если блок был отправлен статическим методом, и у вас нет возможности стереть эту ссылку обратного вызова ??.

В таком случае, следует ли нам избегать использования суррогата 'self'?

Кстати, под «я» суррогат, я хочу сказать:

__block typeof(self) bself = self;

Спасибо !!

Ответы [ 2 ]

5 голосов
/ 01 августа 2011

Ну, во-первых: Если (и только если) ваша причина, по которой вы избегаете использования self или прямого доступа иваров внутри блока, действительно являются циклами сохранения, то вы должны быть в ситуации, подобной

client => objectA => blockWithWeakBackReference

(где => означает «имеет сильную ссылку на»).

В этом случае blockWithWeakBackReference должен вызываться только с помощью objectA, поэтому нет опасности плохого доступа.

Если я правильно понимаю ваш вопрос, вы на самом деле имеете в виду другой сценарий:

  • objectA хочет, чтобы какая-то служба всего приложения выполняла блок от своего имени , если выполняется какое-то предварительное условие.
  • Вы избегаете использования self внутри блока, потому что хотите иметь возможность утилизировать objectA до выполнения блока.

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

В этом случае я бы предложил просто скопировать схему NSNotificationCenter addObserverForName:object:queue:usingBlock: и заставить ваш сервис реализовать пару методов, таких как -(SomeTokenObjectType)addWorkerBlock:(void(^)(whatever-signature-makes-sense-for-you)) и -(void)cancelWorkerBlockWithToken:(SomeTokenObjectType), чтобы поставить в очередь и отменить ваш обратный вызов. блоки.

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

0 голосов
/ 23 октября 2012

"для предотвращения сохранения циклов."

Но у вас действительно есть цикл сохранения, чтобы предотвратить? Думать об этом. Блок сохраняет self (ваш контроллер просмотра). Бэкэнд-вызов сохраняет блок. Но где self удерживает блок?

...