ОК, чтобы сохранить делегата ASIHTTPRequest?

Можно ли сохранить делегата подкласса ASIHTTPRequest?

Я создал подкласс ASIHTTPRequest под названием JSONRequest. Каждый экземпляр JSONRequest является собственным делегатом, обрабатывает обратные вызовы и передает их jsonDelegate, которое является частным свойством JSONRequest, и отвечает на requestFinished:withResult:, где результатом является NSDictionary представление ответа JSON. Для этого я перегрузил setDelegate: в JSONRequest, чтобы сделать super.delegate = self; self.jsonDelegate = newDelegate.

Можно ли сохранить jsonDelegate в этом случае, потому что часто jsonDelegate является контроллером представления, который иногда отключается во время загрузки запроса, если пользователь нажимает «Назад» и т. Д. Я отпущу jsonDelegate в JSONRequest после вызова методов обратного вызова.

Как узнать, что это нормально и не вызовет удерживать петлю.


person ma11hew28    schedule 30.06.2011    source источник


Ответы (3)


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

В этом случае цикл сохранения в какой-то момент всегда будет прерван.

person Steve    schedule 30.06.2011
comment
Только если вы отключите делегат после завершения запроса. - person tc.; 30.06.2011
comment
@tc: из сообщения: я выпущу jsonDelegate в JSONRequest после вызова методов обратного вызова. - person Steve; 30.06.2011
comment
И тогда сервер все равно может возвращать один байт каждые несколько секунд ... Это может быть удобно, но это плохая практика. Сохраните то, что у вас есть. - person tc.; 30.06.2011
comment
неожиданных событий очень трудно ожидать. - person Steve; 30.06.2011
comment
@tc, почему это плохая практика? NSURLConnection сохраняет своего делегата до завершения запроса. - person ma11hew28; 02.07.2011
comment
Согласно Руководству по основам какао Делегирующие объекты не сохраняют (и не должны) сохранять своих делегатов. Возможно, это делается для удобства (если вы просто хотите запустить и забыть, но запустить какой-то код по завершении), но это пахнет плохим дизайном, и я написал глупое количество кода пересылки методов, чтобы избежать таких циклов сохранения. - person tc.; 25.07.2011

Что удерживает запрос? (Очередь операций, может быть? Кто знает?)

В общем, метод «выстрелил-забыл-и-дашь-мне-обратный вызов», который вы, кажется, предлагает, - плохая идея. Если ничто не сохраняет VC, кроме запроса, тогда (если структура вашего приложения не выглядит немного глупой) VC никогда не сможет что-либо сделать с данными, которые он получает, поэтому нет причин для продолжения.

Это также неправильно: принадлежит ли запрос VC, или VC владеет запросом? Я ожидал последнего, поэтому ВК также должен сохранить запрос.

Есть пара исключений:

  • CAAnimation.delegate сохраняется, предположительно потому, что в какой-то момент анимация будет завершена (я не уверен, что произойдет, если это повторяющаяся анимация). То же самое может относиться к делегату анимации UIKit.
  • NSTimer сохраняет свою цель, вероятно, потому, что это делает NSInvocation. (Я написал класс «слабого таймера», чтобы обойти это.)
  • CADisplayLink сохраняет свою цель, предположительно, как NSTimer.

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

Что вы должны делать, так это отслеживать инициированные вами запросы и в процессе освобождения делать что-то вроде

request.delegate = nil;
[request cancel];
self.request = nil;

Точно так же вы должны отменить регистрацию для уведомлений / действий / обратных вызовов KVO в соответствующее время. Есть исключение:

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

Есть исключения из исключения:

  • UIWebView (по крайней мере, в более старых ОС) также сохраняется чем-то другим, возможно, связанным с веб-потоком. Может произойти сбой, если VC исчезнет, ​​пока веб-представление все еще загружается.
  • Обратные вызовы прокрутки UIScrollView также приводят к тому, что представление сохраняется после времени существования VC. Вы можете проверить это, например, удерживая «Готово» и нажимая кнопку «Готово», вы начинаете движение.
person tc.    schedule 30.06.2011
comment
+1, согласился. Лучший ответ, чем мой ... но я просто отвечал на вопрос напрямую ... это лучший общий ответ. - person Steve; 30.06.2011
comment
@tc, спасибо за обстоятельный ответ. Я согласен со многими из них. Однако для сети я считаю, что соединение должно сохранять своего делегата так же, как NSURLConnection сохраняет своего представителя. По этой и многим другим причинам я предпочитаю NSURLConnection ASIHTTPRequest, но переключение на NSURLConnection займет некоторое время. - person ma11hew28; 30.06.2011
comment
Причина сохранения делегата здесь хороша в том, что если навигационный контроллер (NC) выталкивает контроллер представления (делегат), пока запрос все еще загружается, VC может быть отключен, вызывая исключение EXEC_BAD_ACCESS. Но в этом случае я хочу, чтобы делегат сохранялся до завершения загрузки запроса, чтобы делегат мог справиться с успехом или ошибками. - person ma11hew28; 30.06.2011
comment
Вот что я обязательно сделаю: я не выстрелю и не забуду. Вместо этого я сохраню в запросе делегата и отпущу его, когда запрос завершится. Таким образом, если навигационный контроллер (NC) выскакивает и освобождает VC во время запроса, VC все еще сможет обработать завершение запроса через обратные вызовы делегата. Я просто буду обрабатывать обратные вызовы по-разному в зависимости от того, используется ли UIViewController виден. - person ma11hew28; 30.06.2011
comment
Я не думаю, что венчурные капиталисты должны нести ответственность за обработку результатов сетевого запроса. Есть разные способы обойти это, простой - вместо этого использовать сетевой контроллер. - person tc.; 01.07.2011
comment
@tc, хорошо, но я хочу, чтобы VC обновлял свой вид (если он виден или, возможно, только что загружен) на основе ответа сети. Как мне сделать это с сетевого контроллера с уведомлением? Будет ли сетевой контроллер обрабатывать все запросы для одного приложения и просто помечать каждый тип, запрос или что-то еще, чтобы различать их? - person ma11hew28; 02.07.2011
comment
Это зависит от типа запроса, базовой модели данных и того, важен ли запрос (отправленное письмо) или изменение модели (исходящий ящик пуст). В первом случае вы можете захотеть связать виртуальный канал с запросом; в последнем случае изменение модели (уведомление через Core Data или NSNotification) кажется разумным. Разница заключается в том, можно ли иметь разные VC, просматривающие одни и те же данные, и хотите ли вы показать прогресс в обоих из них. - person tc.; 25.07.2011

Я знаю, что этот вопрос изначально касается ASIHTTPRequest, но люди могут наткнуться на эту тему, и это может заставить их подумать, что использование ASIHTTPRequest по-прежнему является лучшей практикой - это не так, фактически разработка остановилась в 2011 году AFAIK.

Использование более современных HTTP-библиотек, которые по умолчанию используют блоки (я предпочитаю AFNetworking), все переменные, указанные в fail / success блоки либо копируются, либо сохраняются до тех пор, пока блоки не будут освобождены. Это избавит вас от всей этой головной боли, связанной с управлением памятью - за исключением случаев, когда вы используете self в одном из блоков, тогда вы создадите цикл сохранения до тех пор, пока блоки не будут освобождены.

person manmal    schedule 04.05.2012