2010-07-20 2 views
2

저는 ASIHTTPRequest 래퍼 (AsyncImageLoader) 배열을 사용하여 UITableView의 셀 이미지를 다운로드하고 있습니다.ASIHTTPRequest dealloc 및 EXC_BAD_ACCESS 문제

평생 ASIHTTPRequests 처리 문제가 있습니다. 그들이 이미지를로드하려고 시도하는 동안 위아래로 스크롤을 계속하면 EXC_BAD_ACCESS가 생겨납니다.

내 래퍼의 모양은 다음과 같습니다. 다시하고 다시 불려 아래로 I가 스크롤을 계속하는 경우 있도록 그리고, indexPath.row % 6 번째 AsyncImageLoader에 대한 cellForRowAtIndexPath에서 호출

@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 : self.requesttargetCell 내가의 이미지를 넣을 세포이며, 속성을 유지있다 동일한 객체, 아직 끝나지 않은 요청을 취소합니다.

하지만 항상 EXC_BAD_ACCESS가 있습니다. 호출 스택에 따르면 ASIHTTPRequest의 markAsFinished에서 에 의해 호출되고 [self.request cancel]에 의해 호출되는 loadImageFromURL:에서 발생합니다. 대부분 ASIHTTPRequest가 이미 릴리스되었습니다 (NSLog를 dealloc에 ​​추가했습니다). 그러나 ASIHTTPRequest가 유지를 throw하여 취소하는 동안 해제되지 않는 것처럼 이것이 가능한지는 알 수 없습니다.

대리자 메서드에서 self.request = nil을 제거하면 EXC_BAD_ACCESS가 없지만 할당 해제없이 ASIHTTPRequests가 계속 만들어 지므로 결국 작동하지 않습니다.

누군가 내가 뭘 잘못하고 있다고 말할 수 있습니까?

+0

, 그건 당신이 잘못하고있는 일입니다. 자신을 발견 한 것처럼 위임 메서드에서 요청을 nil로 설정하는 것은 좋은 생각이 아닙니다. 올바른 위치는 - (void)입니다. viewDidUnload –

답변

1

내 결론 및 기타 답변을 종합하여 나에게 답변.

요청을 취소 할 때 ASIHTTPRequest (또는 iOS)가 약간 불안정한 것처럼 보입니다. 특히 여러 요청이 있고 많은 사람들이 취소되고 꽤 빨리 풀려나는 경우입니다.

해결책으로 나는 많은 요청을 생성하고 더 이상 필요하지 않은 경우이를 취소하는 디자인을 폐기했습니다. 나는 NSOperationQueueASIHTTPRequest을 저장하는 래퍼를 만들었는데, URL을 필터링하여 동일한 요청이 두 번 시작되지 않도록했습니다 (셀이 표시된 경우 이미지가 완전히로드되기 전에 사라지고 다시 표시됩니다). 모든 요청 결과 (즉, 이미지)를 캐시에 저장합니다.

이렇게하면 네트워크 활동이 약간 높아지지만 모든 새로운 요청이 완료 될 때마다 (이미지가 표시되지 않을지라도) 모든 것이 더 명확 해지고 캐시되므로 생성/취소 등의 저글링이 없습니다. 결과적으로 충돌이 발생하지 않습니다. 보기의 할당 해제의이 같은 추가

5

EXC_BAD_ACCESS가 나오는 문제가 발생하면 과다 출시 된 것을 의미합니다. 대부분의 경우 디버거 (Command-Y)를 실행하고 코드가 인 의 마지막 줄이 스택 추적에 표시되면 충돌이 발생하여 어느 개체가 과도하게 릴리스되는지 알 수 있습니다. 그래도 작동하지 않으면 turn on zombies이 필요하며 출시 된 후에 다시 액세스 할 수있는 객체를 확인하십시오. 이것은 거의 항상 올바른 방향으로 당신을 가리킬 것입니다.

부수적으로, 당신이하려는 것을 수행하는 다른 라이브러리가 있습니다. 나는 이것을 많이 사용하지는 않았지만 최소한 잠재력이있는 것 같습니다. 체크 아웃 : SDWebImage. 어쩌면 그것은 당신에게 몇 가지 아이디어를 줄 것입니다.

감사합니다.

+0

답변 해 주셔서 감사합니다. 나는 좀비를 활성화 시켰고 문제는 ASIHTTPRequest의 할당 해제 된 인스턴스에 대해 호출 된 유지 때문에 발생한다고 지적했습니다.AsyncImageLoader에서 하나의 유지 및 릴리스 만 수행되고 ASIHTTPRequest는 제대로 작동 할만큼 충분히 유지되어야하므로 왜 이런 일이 발생하는지 알 수 없습니다. 그 이유는 loadImageFromURL에서 [self.request cancel]을 호출 할 때 self.request가 이미 해제되었지만 requestFinished/Failed 메소드가 주 스레드에서 호출되면 nil로 설정해야합니다. – Jukurrpa

+0

확실하게 말하기는 어렵지만, 아마도 추가로 다시 고려해야 할 필요가 있다고 생각합니다. 여기에 의미하는 바가 있습니다. 현재 요청이 보류 중일 때 테이블보기를 스크롤하면 어떻게됩니까? 테이블 뷰 셀을 통과했습니다. 일단 다운로드가 완료되면 이미지를 채울 것이라고 가정하지만 사용자가 지금 스크롤하면 표시하려는 이미지가 이제는 잘못된 것입니다. 대리자를 전달하면 이미지를 사용할 수있을 때 알림을 보낼 수 있습니다. 그런 다음 위임자는 현재 셀에 해당 이미지를 채워야하는지 여부를 결정할 수 있습니다. –

+0

다른 말로하면, 요점은이 문제를 의도적으로 해결할 수있는 약간의 디자인을 다시 고려해야한다는 것입니다. –

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. 또 다른 요청이 완료 해제하고 통화보다 큐는 할당 취소 요청에 유지

실험으로, 여분의 요청을 한 번 더 보류하려고 시도했습니다. 이로 인해 크래시가 중지되지만 큐가 실행을 멈 춥니 다.

이 ASIHTTPRequest 여전히 어떻게 든 요청을 취소 잘못 취급하지만, 내가 어려운 방법을 보려면 찾는거야 가능성이 있습니다.

업데이트

이 그것을 수정해야합니다 :

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

을 가장 잘 내가 말한 후에는 NSOperationQueue 나쁜 상태로지고 있다고 말할 수 있습니다 시작하지 않았 요청 끝냈다.

+0

안녕하세요, 나는 또한이 버그가 ASIHTTPRequest (또는 iOS)에서 발생했는지 확신합니다. 나열한 작업 체인은 제 상황과 완전히 동일하므로 요청 취소가 불안정 할 수 있습니다. Matt Long이 말했듯이, 나는 오히려 또 다른 디자인을 찾았다. – Jukurrpa

+0

ASIHTTPRequest라고 생각합니다. 해결 방법에 대한 링크를 통해 제 대답을 업데이트했습니다. – JosephH

0

시도 : 당신은 전무 객체에 취소 전화하는거야

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