2010-06-09 7 views
2

이미지를 비동기 적으로로드하고로드 된 UITableViewCell 배치하는 UITableView가 있어요 ("LazyTableImages"자습서에서 것과 거의 동일한 코드를 사용하고 있습니다). 이것은 테이블을 스크롤 할 때 모든 이미지에서 잘 작동하지만 뷰의 첫 번째 이미지는로드되지 않습니다.UITableView 스크롤 할 때까지 NSURLConnection "발사"

NSURLConnection 요청을 실제로 보내는 클래스가 올바르게 호출되고 있으므로 코드가 올바르게 작동합니다 (NSLog를 추가하고 콘솔에 도달했습니다). NSURLConnection은 위임 메서드 (didReceiveData, connectionDidFinishLoading 등)를 호출하지 않습니다. 여기

내 코드입니다 :


HomeController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 

    static NSString *CellIdentifier = @"Cell"; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 

if (cell == nil) { 

     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 

    NSArray *feed = [feeds objectAtIndex: indexPath.row]; 

    /** 
    * Name of person 
    */ 
    [...] 

    /** 
    * Feed entry 
    */ 
    [...] 

    /** 
    * Misc work 
    */ 
    [...] 

} 

FeedRecord *feedRecord = [self.entries objectAtIndex:indexPath.row]; 

if(!feedRecord.image) { 

    if (self.table.dragging == NO && self.table.decelerating == NO) 
    { 
    [self startIconDownload:feedRecord forIndexPath:indexPath]; 
    } 

    cell.imageView.image = [UIImage imageNamed:@"Placeholder.png"];     

} 

    return cell; 
} 

    - (void)startIconDownload:(FeedRecord *)feedRecord forIndexPath:(NSIndexPath *)indexPath 
    { 
     IconDownloader *iconDownloader = [imageDownloadsInProgress objectForKey:indexPath]; 
     if (iconDownloader == nil) 
     { 
      iconDownloader = [[IconDownloader alloc] init]; 
      iconDownloader.feedRecord = feedRecord; 
      iconDownloader.indexPathInTableView = indexPath; 
      iconDownloader.delegate = self; 
      [imageDownloadsInProgress setObject:iconDownloader forKey:indexPath]; 
      [iconDownloader startDownload]; 
      [iconDownloader release]; 
     } 
    } 

IconDownload.m

#import "IconDownloader.h" 
#import "FeedRecord.h" 

#define kAppIconHeight 48 

@implementation IconDownloader 

@synthesize feedRecord; 
@synthesize indexPathInTableView; 
@synthesize delegate; 
@synthesize activeDownload; 
@synthesize imageConnection; 

#pragma mark 

- (void)dealloc 
{ 
    [feedRecord release]; 
    [indexPathInTableView release]; 

    [activeDownload release]; 

    [imageConnection cancel]; 
    [imageConnection release]; 

    [super dealloc]; 
} 

- (void)startDownload 
{ 
NSLog(@"%@ %@",@"Started downloading", feedRecord.profilePicture); // this shows in log 
    self.activeDownload = [NSMutableData data]; 
    // alloc+init and start an NSURLConnection; release on completion/failure 
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest: 
          [NSURLRequest requestWithURL: 
           [NSURL URLWithString:feedRecord.profilePicture]] delegate:self]; 
    self.imageConnection = conn; 
NSLog(@"%@",conn); // this shows in log 
    [conn release]; 
} 

- (void)cancelDownload 
{ 
    [self.imageConnection cancel]; 
    self.imageConnection = nil; 
    self.activeDownload = nil; 
} 


#pragma mark - 
#pragma mark Download support (NSURLConnectionDelegate) 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
NSLog(@"%@ %@",@"Got data for", feedRecord.profilePicture); 
    [self.activeDownload appendData:data]; 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
NSLog(@"%@",@"Fail!"); 
// Clear the activeDownload property to allow later attempts 
    self.activeDownload = nil; 

    // Release the connection now that it's finished 
    self.imageConnection = nil; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    NSLog(@"%@ %@",@"Done", feedRecord.profilePicture); 
    // Set appIcon and clear temporary data/image 
    UIImage *image = [[UIImage alloc] initWithData:self.activeDownload]; 

self.feedRecord.image = image; 

    self.activeDownload = nil; 

[image release]; 

    // Release the connection now that it's finished 
    self.imageConnection = nil; 

NSLog(@"%@ %@",@"Our delegate is",delegate); 
    // call our delegate and tell it that our icon is ready for display 
    [delegate feedImageDidLoad:self.indexPathInTableView]; 
} 

@end 

다른 사람이 이와 같은 경험이 있거나 내 코드로 문제를 식별 할 수 있습니까? 감사!

답변

0

NSURLConnection을 시작하지 마십시오. -[NSURLConnection initWithRequest:delegate:startImmediately:]으로 초기화하거나 초기화 후 수동으로 -[NSURLConnection start]으로 호출하십시오.

+0

아니 단순히 "일반 모드"에서 연결을 등록합니다. 내가 가진 코드는 요청을 초기화하고 URL을 즉시 다운로드하기 시작합니다. (이 방법에 대한 Apple의 설명서 : "초기화 된 URL 연결을 반환하고 URL 요청에 대한 데이터를로드하기 시작합니다."). [NSURLConnection start]도 작동하지 않습니다 : ( – Simon

+0

죄송합니다. 문서를 잘못 읽었습니다. 실제로 코드에 문제가 없습니다. startDownload 메서드에 중단 점을 설정하고 모든 것이 예상대로 있는지 확인 했습니까? – Alfonso

0

여기를 보시려면 여기를 클릭하십시오 : http://www.depl0y.com/?p=345 아마도 도움이 될 것입니다.

편집 : 네, 저를 위해 일하고 있습니다. 나 또한 당신을 위해 일하고 있는지 또는 더 많은 정보가 필요한지 알려주십시오.

0

동일한 문제가 있습니다. 또한 거의 동일한 코드를 사용합니다 (Apple 샘플 LazyTableImages에서 제공).

Apple의 테스트 프로젝트 코드가 작동하지만 프로젝트에서 작동하지 않지만 방금 Apple 코드 사본을 만들었지 만. 내가 찾은 무엇

입니다 :뿐만 아니라 IconDownload.m의 startDownload로 : (두 프로젝트에서), 나는 그것이 애플의 샘플에서 메인 스레드이지만, 사실을 발견 나는

NSLog(@"Is%@ main thread", ([NSThread isMainThread] ? @"" : @" NOT")); 
cellForRowAtIndexPath에서

을 사용하는 경우 내 코드의 기본 스레드가이 아닙니다.

이것은 문제 일 수 있습니다.

어떤 아이디어로 해결할 수 있습니까?


EDIT !!! 해결!

난 그냥 cellForRowAtIndexPath에

NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:entry.imageURL, @"imageURL", indexPath, @"indexPath", nil]; 
[self performSelectorOnMainThread:@selector(startIconDownload:) withObject:info waitUntilDone:NO]; 

를 사용하여 메인 스레드를 강제로 : 당신은 방법에 하나 개 이상의 인수를 보내 사전이 필요합니다.

코드에서 유사한 해결책을 사용할 수 있습니다. 내 코드

[self startIconDownload:feedRecord forIndexPath:indexPath]; 

및 startIconDownload 수정 : 줄 바꾸기이

- (void)startIconDownload:(NSDictionary *)info 
{ 
    NSString *url = [info objectForKey:@"imageURL"]; 
    NSIndexPath *indexPath = [info objectForKey:@"indexPath"]; 
    ... 
} 

일부 변수와 같은 앱에 다른 수의 나.

그러나 나는 애플의 샘플에서 메인 스레드를 강제하지 않고 왜 작동하는지 이해할 수 없다.

아이디어가 있으십니까?

1

당신이있는 NSURLConnection의 시작 메소드를 호출하지 않는이 코드

[tableView performSelector:@selector(reloadData) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES]; 

대신

[tableView reloadData]; 
1

을 사용할 수 있습니다 당신은 당신의 startDownload 방법으로 객체 생성.

그것을하십시오 : 또한 생성자를 사용할 수 있습니다

- (void)startDownload 
{ 
    NSLog(@"%@ %@",@"Started downloading", feedRecord.profilePicture); // this shows in log 
    self.activeDownload = [NSMutableData data]; 
    // alloc+init and start an NSURLConnection; release on completion/failure 
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest: 
          [NSURLRequest requestWithURL: 
          [NSURL URLWithString:feedRecord.profilePicture]] delegate:self]; 
    self.imageConnection = conn; 
    NSLog(@"%@",conn); // this shows in log 
    [conn start]; 
    [conn release]; 
} 

: initWithRequest:delegate:startImmediately: 또한

이 다운로드 때문에 그들은 사용자가 스크롤하면 실행하는 실행 루프의 차단됩니다.

[conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 

에서 추출 : how-to-avoid-blocked-downloads-during-scrolling

관련 문제