ASIHTTPRequest dealloc и проблема EXC_BAD_ACCESS - PullRequest
2 голосов
/ 20 июля 2010

Я использую массив упаковщиков ASIHTTPRequest (AsyncImageLoader) для загрузки изображений для ячеек в UITableView.

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

Вот как выглядит моя оболочка.self.request имеет свойство retain, targetCell - это ячейка, в которую я хочу поместить изображение:

@implementation AsyncImageLoader
- (void)loadImageFromURL:(NSString*)fileName target:(ResultTableViewCell*)targetCell {
    // check for cached images, etc

    NSURL* url = [NSURL URLWithString:fileName];
    [self.request cancel];
    self.request = [ASIHTTPRequest requestWithURL:url];
    self.request.delegate = self;
}

- (void)startLoading {
    [self.request startAsynchronous];
}

- (void)cancel {
    [self.request cancel];
    self.request = nil;
}

- (void)requestFinished:(ASIHTTPRequest*)requestDone {
    // cache image, set cell image...

    self.request = nil;
}

- (void)requestFailed:(ASIHTTPRequest*)requestDone {
    // handle answer as well

    self.request = nil;
}
@end

loadImageFromURL вызывается в cellForRowAtIndexPath для indexPath.row % 6 th AsyncImageLoader, поэтому если япродолжайте прокручивать вверх и вниз, он вызывается снова и снова с одним и тем же объектом, отменяя запросы, поскольку они еще не закончены.

Но я всегда получаю EXC_BAD_ACCESS.В соответствии со стеком вызовов это происходит в ASIHTTPRequest markAsFinished, вызываемом failWithError, вызываемым [self.request cancel] в loadImageFromURL:.Большую часть времени ASIHTTPRequest уже был выпущен (я добавил NSLog в его dealloc), но я не понимаю, как это возможно, так как кажется, что ASIHTTPRequest выбрасывает сохранения, поэтому он не освобождается при отмене.У меня нет EXC_BAD_ACCESS, если я удаляю self.request = nil в методах делегатов, но поскольку запросы ASIHTTP продолжают создаваться без освобождения, они вообще не работают.

Может кто-нибудь сказать мне, что я делаю неправильно

Ответы [ 4 ]

5 голосов
/ 20 июля 2010

Когда вы сталкиваетесь с проблемой, когда получаете EXC_BAD_ACCESS, это означает, что вы что-то переоценили.В большинстве случаев вам просто нужно запустить отладчик (Command-Y) и увидеть последнюю строку ваш код в трассировке стека, когда он падает, чтобы узнать, какой объект перевыпущен.Если это не сработает, то вам нужно включить зомби и посмотреть, к какому объекту снова обращаются после его освобождения.Это почти всегда укажет вам правильное направление.

В качестве примечания, есть некоторые другие библиотеки, которые делают то, что вы пытаетесь сделать.Я не использовал это много, но похоже, что у него есть потенциал, по крайней мере.Проверить: SDWebImage .Может быть, это даст вам некоторые идеи.

С наилучшими пожеланиями.

2 голосов
/ 21 июля 2010

Это звучит очень похоже на сбой, который я вижу.

Я пока не уверен, в чем причина, но я твердо верю, что это не связано с клиентским кодом (т. Е. Это либо в ASIHTTPRequest, либо в ОС).

Я исправил некоторые проблемы в запросе asi http, но этот сбой сохраняется.

Я пытался получить помощь на форумах Apple здесь:

https://devforums.apple.com/thread/59843?tstart=0

Вот как выглядит сбой для меня:

#2  0x32c02e14 in CFRetain ()
#3  0x32c709b6 in __CFTypeCollectionRetain ()
#4  0x32c06c60 in _CFArrayReplaceValues ()
#5  0x32b0994c in -[NSCFArray insertObject:atIndex:] ()
#6  0x32b098f0 in -[NSCFArray addObject:] ()
#7  0x32b709f0 in __chooseAll ()
#8  0x32b71bde in __finishedOp ()
#9  0x32b26636 in +[NSOperation observeValueForKeyPath:ofObject:change:context:] ()
#10 0x32b265aa in NSKVONotify ()
#11 0x32b13306 in -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] ()
#12 0x0007d6ec in -[ASIHTTPRequest markAsFinished] (self=0x5a7cc40, _cmd=0xa1710) at ASIHTTPRequest.m:2817
#13 0x00077e02 in -[ASIHTTPRequest failWithError:] (self=0x5a7cc40, _cmd=0x330cdfc4, theError=0x248130) at ASIHTTPRequest.m:1708
#14 0x000712dc in -[ASIHTTPRequest cancel] (self=0x5a7cc40, _cmd=0x322b4298) at ASIHTTPRequest.m:515
#15 0x0008884c in -[UIHTTPImageView setImageWithURL:placeholderImage:] (self=0x5a7c9d0, _cmd=0xa3f0c, url=0x5aa7760, placeholder=0x0) at UIHTTPImageView.m:21
#16 0x0006183c in -[MeetingView tiledScrollView:tileForRow:column:resolution:] (self=0x5a32560, _cmd=0x9bfac, tiledScrollView=0x5a74570, row=1, column=0, resolution=0) at MeetingView.m:1053
#17 0x0000475e in -[TiledScrollView layoutSubviews] (self=0x5a74570, _cmd=0x32299680) at TiledScrollView.m:181
#18 0x31515f32 in -[UIView(CALayerDelegate) _layoutSublayersOfLayer:] ()
#19 0x32c29ffa in -[NSObject performSelector:withObject:] ()
#20 0x30964798 in -[CALayer layoutSublayers] ()
#21 0x30964568 in CALayerLayoutIfNeeded ()
#22 0x30959b62 in CA::Context::commit_transaction ()
#23 0x3095997a in CA::Transaction::commit ()
#24 0x3097f164 in CA::Transaction::observer_callback ()
#25 0x32c702a0 in __CFRunLoopDoObservers ()
#26 0x32c23bb0 in CFRunLoopRunSpecific ()
#27 0x32c234e0 in CFRunLoopRunInMode ()
#28 0x30d620da in GSEventRunModal ()
#29 0x30d62186 in GSEventRun ()
#30 0x314d54c8 in -[UIApplication _run] ()
#31 0x314d39f2 in UIApplicationMain ()
#32 0x0000245c in main (argc=1, argv=0x2ffff5b4) at main.m:14

Из того, что я могу сказать, действия выглядят примерно так:

  1. Запрос создан и запущен, и, следовательно, добавлен в очередь
  2. Запрос отменяется до его запуска
  3. Запрос успешно отменен, удален из очереди и освобожден
  4. Другой запрос завершени очередь, кроме вызовов, сохраняется в освобожденном запросе

В качестве эксперимента я попытался сохранить запросы еще один раз - это останавливает сбой, но очередь перестает работать.

ЭтоВозможно, что ASIHTTPReqUest все еще неправильно обрабатывает запрос на отмену, но мне трудно понять, как.

Обновление

Это должно исправить это:

http://github.com/jogu/asi-http-request/commit/887fcad0f77e9717f003273612804a9b9012a140

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

1 голос
/ 21 июля 2010

Отвечая перед собой как синтез моего заключения и других ответов.

Кажется, что ASIHTTPRequest (или, может быть, iOS) немного нестабилен при отмене запросов, особенно когда есть несколько запросов, и многие из них отменяются и выпускаются довольно быстро.

В качестве решения я отказался от создания множества запросов и их отмены, если они больше не нужны. Я сделал обертку, хранящую ASIHTTPRequest s в NSOperationQueue, которая также фильтрует URL-адреса, чтобы один и тот же запрос не запускался дважды (в случае, если ячейка появляется, затем исчезает до полной загрузки изображения и отображается снова). Я храню все результаты запросов (т.е. изображения) в кэше.

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

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

попробуйте добавить что-то вроде этого в dealloc вашего взгляда:

    [self.thumbnailRequest cancel];
self.thumbnailRequest.delegate = nil;
[self.thumbnailRequest setDidFinishSelector:NULL];
[self.thumbnailRequest setDidFailSelector:NULL];
self.thumbnailRequest = nil;
...