2011-12-01 4 views
0

UITableView은 TBPostSnapCell이라는 약 10 개의 하위 클래스로 구성된 UITableViewCell으로 구성되어 있습니다. 각 셀은 초기화 될 때 GCD을 통해 다운로드되거나 사용자의 문서 디렉토리에 저장된 캐시에서 검색된 UIImage으로 두 개의 변수를 설정합니다.UITableView 및 GCD로 지연 줄이기

어떤 이유인지, 이로 인해 tableView에서 눈에 띄는 지체가 발생하여 & 테이블의 UX가 중단됩니다.

이 지연을 줄일 수있는 방법을 알려주십시오.

있는 tableView ... cellForRowAtIndexPath :

if (post.postType == TBPostTypeSnap || post.snaps != nil) { 

     TBPostSnapCell *snapCell = (TBPostSnapCell *) [tableView dequeueReusableCellWithIdentifier:snapID]; 

     if (snapCell == nil) { 

      snapCell = [[[NSBundle mainBundle] loadNibNamed:@"TBPostSnapCell" owner:self options:nil] objectAtIndex:0]; 

      [snapCell setPost:[posts objectAtIndex:indexPath.row]]; 

      [snapCell.bottomImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d", (indexPath.row % 6) +1]]]; 
     } 

    [snapCell.commentsButton setTag:indexPath.row]; 
    [snapCell.commentsButton addTarget:self action:@selector(comments:) forControlEvents:UIControlEventTouchDown]; 
    [snapCell setSelectionStyle:UITableViewCellSelectionStyleNone]; 

    return snapCell; 
} 

TBSnapCell.m

- (void) setPost:(TBPost *) _post { 

    if (post != _post) { 
     [post release]; 
     post = [_post retain]; 
    } 
    ... 

    if (self.snap == nil) { 

     NSString *str = [[_post snaps] objectForKey:TBImageOriginalURL]; 
     NSURL *url = [NSURL URLWithString:str]; 
     [TBImageDownloader downloadImageAtURL:url completion:^(UIImage *image) { 
      [self setSnap:image]; 
     }]; 
    } 

    if (self.authorAvatar == nil) { 
     ... 
     NSURL *url = [[[_post user] avatars] objectForKey:[[TBForrstr sharedForrstr] stringForPhotoSize:TBPhotoSizeSmall]]; 

     [TBImageDownloader downloadImageAtURL:url completion:^(UIImage *image) { 
      [self setAuthorAvatar:image]; 
     }]; 
     ... 
    } 

} 

TBImageDownloader.m

+ (void) downloadImageAtURL:(NSURL *)url completion:(TBImageDownloadCompletion)_block { 

    if ([self hasWrittenDataToFilePath:filePathForURL(url)]) { 
     [self imageForURL:filePathForURL(url) callback:^(UIImage * image) { 
      _block(image); //gets UIImage from NSDocumentsDirectory via GCD 
     }]; 
     return; 
    } 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); 
    dispatch_async(queue, ^{ 
     UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)]; 
      _block(image); 
     }); 
    }); 
} 

답변

2
DISPATCH_QUEUE_PRIORITY_HIGH 변환됩니다 시도

우선 (일명 ONG 가장 중요한 WORK DISPATCH_QUEUE_PRIORITY_LOW와 같은 것으로 모든 것을 잊어 버렸습니다.

문제가 해결되지 않으면 dispatch_sources를 통해 http 트래픽을 시도 할 수는 있지만 많은 작업이 필요합니다.

세마포어로 비행 중 http 페치 수를 제한하려고 시도 할 수도 있습니다. 실제 트릭은 "좋은"숫자가 네트워크, CPU 및 메모리에 따라 달라 지므로 최상의 제한값을 결정합니다 압력. 벤치 마크 2, 4 및 8을 몇 가지 구성으로 설정하고 일반화 할 패턴이 충분한 지 확인하십시오. 그대로

static dispatch_once_t once; 
static dispatch_queue_t queue = NULL; 
dispatch_once(&once, ^{ 
    queue = dispatch_queue_create("com.blah.url-fetch", NULL); 
}); 

코드의 나머지를 남겨 : 좋아

는 하나, 함께 queue = ...를 교체하려고 할 수 있습니다. 이것은 가장 덜 터지기 쉽지만 이미지를 매우 빠르게로드하지는 못합니다. 더 일반적인 경우에 대한

은, 난 그냥 준 변경을 버리고, 우리는이 작업을합니다 :

dispatch_async(queue, ^{ 
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)]; 
     _block(image); 
    }); 
}); 

로 교체 :

static dispatch_once_t once; 
static const int max_in_flight = 2; // Also try 4, 8, and maybe some other numbers 
static dispatch_semaphore_t limit = NULL; 
dispatch_once(&once, ^{ 
    limit = dispatch_semaphore_create(max_in_flight); 
}); 
dispatch_async(queue, ^{ 
    dispatch_semaphore_wait(limit, DISPATCH_TIME_FOREVER); 
    UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]; 
    // (or you might want the dispatch_semaphore_signal here, and not below) 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)]; 
     _block(image); 
     dispatch_semaphore_signal(limit); 
    }); 
}); 

참고 : I에게 피난처를 심지어이 코드가 컴파일되었는지 확인하기 위해이 코드를 테스트하지 않았습니다. 작성된대로 두 개의 스레드가 두 개의 중첩 된 블록에서 대량의 코드를 실행하는 것을 허용합니다. dispatch_semaphore_signal을 주석 처리 된 행으로 옮길 수 있습니다. 이렇게하면 두 개의 가져 오기/이미지 생성으로 제한되지만 이미지 데이터를 파일에 쓰고 _block 콜백을 호출하는 것과 중복 될 수 있습니다.

당신은 파일 I/O를 많이합니다. 플래시에서 더 빠른 디스크를 사용하면 디스크가 더 빨라졌지만 여전히 성능이 좋은 곳을 찾고 있다면 다른 곳으로 공격 할 수 있습니다. 예를 들어 UIImage를 메모리 부족 상태로 유지하고 디스크에 기록 할 때까지 메모리에 UIImage를 보관할 수 있습니다.

+0

감사합니다. 우선 순위를 낮음으로 설정해 보았습니다. 지연 시간이 약간 줄어든 것 같습니다. 세마포어를 사용하는 예를 들려 주시겠습니까? –

+0

예제가 제공됩니다. 행운을 빌어 요. – Stripes

+0

샘플 코드를 제공해 주셔서 감사합니다.이 테이블은 현재 지연 시간이 상당히 단축되어 실행 중입니다! 아직 약간의 지연이 남아 있지만 석영 코어 드로잉과 관련이 있다고 생각합니다. –