Блокировка цепочки

У меня есть два экземпляра разных классов, которым необходимо добавить блок завершения для конкретной операции. Я попытаюсь объяснить проблему в целом, а не объяснять все, что пытается сделать мое приложение.

Контроллер вида вызывает вызов класса менеджера ресурсов для сохранения ресурса. Затем диспетчер ресурсов вызывает класс ресурса, который нужно сохранить, чтобы получить сетевую операцию для сохранения.

Экземпляр ресурса создает операцию и дает ей блок завершения, который будет влиять на состояние ресурса при его запуске.

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

Вот фрагмент метода сохранения в менеджере:

-(void)save:resource withCompletion:completion { . . . NSOperation *operation = [resource operationForSave]; NSOperation __weak *weakOperation = operation; void(^__weak resourceCompletion)(void)= operation.completionBlock; [operation setCompletionBlock:^{ if (resourceCompletion) { resourceCompletion(); } if (completion) { if (weakOperation.error) { completion(NO, operation.error); } else { completion(YES, nil); } } }]; . . . // add the operation to a network operation queue } 

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

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

Любой вход был бы очень оценен.

Код, который вы опубликовали, вероятно, не будет работать. Когда вы заменяете блок завершения операции своим собственным блоком, вы, вероятно, удаляете единственную сильную ссылку на исходный блок завершения (заданный ресурсом). Таким образом, ваша переменная resourceCompletion , будучи слабой, станет нулевой к моменту setCompletionBlock: возвращает.

Простое исправление resourceCompletion должно решить проблему. Но если вы хотите сделать это более чистым способом, измените сообщение operationForSave (на ресурсе), чтобы взять сам блок завершения:

 __block NSNetworkOperation *operation = [resource operationForSaveWithCompletion:^{ NSError *error = operation.error; completion(error == nil, error); // Break the retain cycle between this block and the operation object. operation = nil; }]; 

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

Если вы не хотите или не можете изменять API ресурса, вы все равно можете упростить свой код, исключив слабые ссылки:

 __block NSNetworkOperation *operation = [resource operationForSave]; __block void (^priorCompletion)(void) = operation.completionBlock; operation.completionBlock = ^{ if (priorCompletion) { priorCompletion); // Break possible retain cycle. priorCompletion = nil; } NSError *error = operation.error; completion(error == nil, error); // Break the retain cycle between this block and the operation object. operation = nil; }; 

Кроме того, я искренне надеюсь, что у вас действительно нет класса NSNetworkOperation , потому что Apple резервирует префикс NS (и все другие двухбуквенные префиксы) для собственного использования.

  • Почему мой IBAction меняет текст ярлыка, который не работает?
  • Создание подкласса объекта NSManagedObject
  • GKGameCenterViewController всегда показывает вызовы вместо лидеров
  • Изменить цвет оттенка клавиатуры для UITextField
  • Метод iTunes для поиска? bundleId не работает для моего приложения
  • Обрезать изображение с помощью прямоугольного прямоугольника выбранной области?
  • Примеры контроллера контейнера
  • Взаимодействие с addChildViewController и надписью контроля над UINavigationController
  • Получить высоту кадра без высоты навигационной панели и высоты панели табуляции в иерархии более глубокого представления
  • Отмена интерактивного жестов по умолчанию UINavigationController не вызывает методы UINavigationControllerDelegate
  • Почему responseSoSelector не работает для меня в этом случае?
  • Давайте будем гением компьютера.