Очистка зависания NSURLConnections, когда контроллер освобожден - PullRequest
3 голосов
/ 08 сентября 2010

У меня есть контроллер, который делает HTTP-запросы GET, используя пользовательский класс, который действует как делегат для NSURLConnection. После сбоя или завершения NSURLConnection пользовательский класс вызывает методы контроллера и передает объект NSData полученных данных.

Я столкнулся с проблемой, когда контроллер в действии динамически создается и помещается в стек контроллера навигации. Этот контроллер выполняет HTTP-запрос GET в своем методе viewDidLoad. Если пользователь быстро нажимает «назад» на панели навигации, этот контроллер освобождается. Если это произойдет до того, как запрос HTTP GET завершится, полученный обратный вызов NSURLConnection станет вызовом метода для объекта dealloc, что приведет к EXC_BAD_ACCESS.

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

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

Ответы [ 3 ]

2 голосов
/ 08 сентября 2010

Если я правильно понимаю, вам просто нужно сделать [whatConnection cancel] в вашем методе viewDidUnload или dealloc.Это отменяет соединение.Это почти то же самое, если у вас есть пользовательский объект загрузчика, например, для большого изображения, которое использует NSURLConnection.Создайте метод cancel для вашего класса (который отменяет соединение и освобождает его) и вызовите его в методе dealloc вашего контроллера.Вам также следует использовать флаг bool, похожий на wasCanceled, и не вызывать какой-либо метод из делегата пользовательского объекта, если wasCanceled был установлен из вашего метода cancel.(У вас есть только слабый указатель на ваш делегат, поэтому он, вероятно, освобождается, когда какой-то другой объект вызывает ваш метод отмены).Я предполагаю, что делегатом для вашего пользовательского объекта является контроллер представления.У меня было несколько таких загрузчиков, и это работало нормально, без утечек, даже если я быстро отменил загрузку.

@interface CompaniesDownloader : NSObject /*<NSXMLParserDelegate>*/
{
    id<CompaniesDownloaderDelegate> delegate; //a view controller is the delegate
    NSMutableArray *companies;

    BOOL isWorking;    
    BOOL wasCanceled;   

    @private

    //url connection object
    NSURLConnection *companiesConnection;

    //this is where i put the binary data that gets transformed into xml
    NSMutableData *webData;

    //temporary string used when parsing xml
    NSMutableString *tmpString;

    //temporary company used when parsing xml
    Company *tmpCompany;
}

В реализации:

-(void) cancel
{
  [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible: FALSE];

  wasCanceled = TRUE;
  [companiesConnection cancel];
  [webData release];
  webData = nil;
  self.companiesConnection = nil; //OR [companiesConnection release]; companiesConnection=nil;
  isWorking = FALSE;
}
0 голосов
/ 08 сентября 2010

Если пользователь быстро нажимает «назад» на панели навигации, этот контроллер освобождается.Если это произойдет до того, как запрос HTTP GET завершится, результирующий обратный вызов NSURLConnection станет вызовом метода для объекта dealloc, что приведет к EXC_BAD_ACCESS.

Когда пользователь нажмет кнопку возвратазарегистрируйте класс контроллера представления от того, чтобы быть делегатом для этого объекта.(Сохраняйте ссылку на объект в классе контроллера представления, чтобы вы могли сделать что-то вроде someObject.delegate = nil;).Вы можете сделать это в методе dealloc контроллера представления.

0 голосов
/ 08 сентября 2010

Вам нужно сохранить контроллер представления, когда вы делаете запрос, и освобождать, когда запрос get завершен.

YourViewController.m
- (void)callGetRequest {
   [self retain];
}

- (void)didFinishAllGetTask {
   [self release];
}
...