2

ASIHTTPRequest ラッパー (AsyncImageLoader) の配列を使用して、UITableView のセルの画像をダウンロードしています。

ASIHTTPRequests の有効期間の処理に問題があります。それらを解放すると、画像をロードしようとしている間に上下にスクロールし続けると、EXC_BAD_ACCESS が発生します。

これが私のラッパーの外観です。self.request保持プロパティ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

loadImageFromURLth AsyncImageLoader に対して呼び出されるcellForRowAtIndexPathため、indexPath.row % 6上下にスクロールし続けると、同じオブジェクトで何度も呼び出され、まだ終わっていないのでリクエストがキャンセルされます。

しかし、私は常に EXC_BAD_ACCESS を持っています。コール スタックによると、ASIHTTPRequest のmarkAsFinishedで呼び出され、 infailWithErrorで呼び出されます。ほとんどの場合、ASIHTTPRequest は既に解放されています (dealloc に NSLog を追加しました) が、ASIHTTPRequest が保持をスローしているように見えるため、キャンセル中に解放されないため、これがどのように可能かわかりません。[self.request cancel]loadImageFromURL:

デリゲート メソッドを削除すると EXC_BAD_ACCESS はありませんが、ASIHTTPRequests はself.request = nil割り当てを解除せずに作成され続けるため、まったく機能しなくなります。

誰かが私が間違っていることを教えてもらえますか?

4

4 に答える 4

5

EXC_BAD_ACCESSを取得する問題が発生した場合は、何かを過剰にリリースしたことを意味します。ほとんどの場合、デバッガー(Command-Y)を実行し、クラッシュ時にスタックトレースのコードの最後の行を確認して、どのオブジェクトがオーバーリリースされているかを確認する必要があります。それでも問題が解決しない場合は、ゾンビをオンにして、解放された後にどのオブジェクトに再度アクセスしているかを確認する必要があります。これはほとんどの場合、正しい方向を示します。

ちなみに、あなたがやろうとしていることを実行する他のライブラリがいくつかあります。私はこれをあまり使用していませんが、少なくとも可能性があるようです。チェックアウト:SDWebImage。多分それはあなたにいくつかのアイデアを与えるでしょう。

よろしくお願いします。

于 2010-07-20T17:06:27.663 に答える
2

これは、私が見ているクラッシュのように聞こえます。

原因はまだわかりませんが、クライアント コードとは関係がないと確信しています (つまり、ASIHTTPRequest または OS のいずれかにある)。

asi http リクエストのいくつかの問題を修正しましたが、このクラッシュは残ります。

ここのアップルフォーラムで支援を得ようとしています:

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. 別のリクエストが完了し、呼び出しよりもキューが割り当て解除されたリクエストで保持されます

実験として、リクエストの保持をもう 1 回試みました。これにより、クラッシュは停止しますが、キューの実行は停止します。

ASIHTTPRequest がまだキャンセル リクエストの処理を誤っている可能性がありますが、その方法を理解するのは難しいと感じています。

アップデート

これで修正されるはずです:

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

私が知る限り、NSOperationQueue は、開始されていない要求が終了したと通知された後、悪い状態になっていました。

于 2010-07-21T18:40:31.320 に答える
1

私の結論と他の答えの統合として、自分自身に答えます。

ASIHTTPRequest (またはおそらく iOS) は、リクエストをキャンセルするとき、特にいくつかのリクエストがあり、多くのリクエストがキャンセルされてかなり速く解放される場合、少し不安定なようです。

解決策として、多くのリクエストを作成し、不要になった場合はキャンセルするという設計を破棄しました。ASIHTTPRequests を aに格納するラッパーを作成しましたNSOperationQueue。これは、同じ要求が 2 回開始されないように URL もフィルター処理します (セルが表示された場合、画像が完全に読み込まれる前に消え、再度表示されます)。すべてのリクエスト結果 (画像など) をキャッシュに保存します。

これにより、ネットワーク アクティビティがわずかに高くなる可能性がありますが、すべての新しい要求が完了し (画像が表示されない場合でも) キャッシュされるため、他のすべてがより明確になるため、作成/キャンセル/などをジャグリングする必要はありません。さらにクラッシュ。

于 2010-07-21T19:34:25.197 に答える
0

ビューの dealloc に次のようなものを追加してみてください。

    [self.thumbnailRequest cancel];
self.thumbnailRequest.delegate = nil;
[self.thumbnailRequest setDidFinishSelector:NULL];
[self.thumbnailRequest setDidFailSelector:NULL];
self.thumbnailRequest = nil;
于 2012-10-15T12:40:21.557 に答える