2013-05-07 3 views
1

GCD를 사용하여 백그라운드 스레드에서 UITableView 데이터를로드하지만 사용자 정의 UITableViewCell의 데이터를 혼합합니다. 셀의 titleLabel 및 imageView는 문제가 없지만 모든 셀에서 textLabel (부제목)이 잘못되었습니다. 데이터가 메인 쓰레드에로드되고 데이터가 여러 배열로부터 온 것이 아니기 때문에 이런 일은 일어나지 않습니다. 그래서 나는 GCD를 사용하고 있기 때문에 추측 할 수 있습니다.GIT를 사용할 때 UITableViewCell의 데이터가 섞여 있습니다.

첫째, 나는 setUpTableForAlbumsFD 선택이

- (void)setUpTableForAlbumsFD 
{ 
// __block CLProgressIndeterminateView *clP = [[CLProgressIndeterminateView alloc] initWithFrame:CGRectMake(325, tableScrollView.frame.size.height/2, 310, 20)]; 
// [tableScrollView addSubview:clP]; 
// [clP startAnimating]; 
type = @"Albums"; 
queryAlbums = [MPMediaQuery albumsQuery]; 
[queryAlbums setGroupingType:MPMediaGroupingAlbum]; 

mainArrayAlbum = [[NSMutableArray alloc] init]; 
otherArrayAlbum = [[NSMutableArray alloc] init]; 
theOtherArrayAlbum = [[NSMutableArray alloc] init]; 

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
NSString *documentsPath = [paths objectAtIndex:0]; 

NSArray *fullArray = [queryAlbums collections]; 
for (MPMediaItemCollection *collection in fullArray) 
{ 
    item = [collection representativeItem]; 
    NSString *albumName = [item valueForProperty:MPMediaItemPropertyAlbumTitle]; 
    NSString *albumArtist = [item valueForProperty:MPMediaItemPropertyArtist]; 

    NSString *filePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", albumName]]; 
    Album *album = [[Album alloc] init]; 
    album.albumTitle = albumName; 
    album.albumArtwork = [UIImage imageImmediateLoadWithContentsOfFile:filePath]; 
    if (album.albumTitle.length > 4) 
    { 
     if ([album.albumTitle hasPrefix:@"The "]) 
     { 
      album.albumOrderTitle = [album.albumTitle substringFromIndex:4]; 
     } 
     else 
     { 
      album.albumOrderTitle = album.albumTitle; 
     } 
    } 
    else 
    { 
     album.albumOrderTitle = album.albumTitle; 
    } 
    album.albumArtist = albumArtist; 
    if (![mainArrayAlbum containsObject:album]) 
    { 
     [mainArrayAlbum addObject:album]; 
    } 

} 
} 

앨범 사용자 정의 클래스는 데이터를 단지 컨테이너입니다 ... 그래서입니다

- (void)setUpTableForAlbums 
{ 
    dispatch_async(dispatch_get_global_queue(0, 0),^
       { 
        [self setUpTableForAlbumsFD]; 
        dispatch_async(dispatch_get_main_queue(),^
            { 
             [albumTable reloadData]; 
            }); 
       }); 
} 

... 그래서 같이 NSOperationQueue를 설정 .

cellForRowAtIndex 경로 방법은

MasterCellAlbum *albumCell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; 
    if (!albumCell) 
    { 
     albumCell = [[MasterCellAlbum alloc] initWithStyle:nil reuseIdentifier:@"Cell"]; 
    } 
    alphabet = [self alphabet:@"album" withIndex:YES]; 
    [albumCell setSelectionStyle:UITableViewCellEditingStyleNone]; 
    NSString *alpha = [alphabet objectAtIndex:indexPath.section]; 
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.albumOrderTitle beginswith[c] %@", alpha]; 
    NSArray *predict = [mainArrayAlbum filteredArrayUsingPredicate:predicate]; 
    [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 


    Album *album1 = [predict objectAtIndex:indexPath.row]; 
    albumCell.titleLabel.text = album1.albumTitle; 
    albumCell.textLabel.text = album1.albumArtist; 
    albumCell.avatarImageView.image = album1.albumArtwork; 

    longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(albumLittleMenu:)]; 
    [albumCell addGestureRecognizer:longPress]; 
    return albumCell; 

내가 제대로 GCD를 사용하고 ... 그래서, 또는 내가 그 일을해야 또 다른 방법은 무엇입니까?

답변

1

Yikes. 많은 것들이 있습니다, 우리는이 코드에 대해 이 흥미 롭습니다. 이제 첫 번째 방법부터 시작하자 :

NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init]; 
NSInvocationOperation *operation = [NSInvocationOperation alloc]; 

operation = [operation initWithTarget:self selector:@selector(setUpTableForAlbumsFD) object:nil]; 
[operation setCompletionBlock:^ 
{ 
    [albumTable reloadData]; 
}]; 
[operationQueue addOperation:operation]; 
operation = nil; 

은 내가 당신이 할 묶는 있다고 생각하면 백그라운드에서 -setUpTableForAlbumsFD 방법을 실행하고, 그것이 끝나면 다음의있는 tableView를 다시로드합니다.

먼저 completionBlock은 주 스레드에서 실행되지 않습니다.이 곳에서 주저 스레드는 -reloadData을 호출해야합니다. 문서 설명 :

완료 블록의 정확한 실행 컨텍스트는 보장되지 않지만 일반적으로 보조 스레드입니다. 따라서이 블록을 사용하여 매우 특정한 실행 컨텍스트가 필요한 작업을 수행해서는 안됩니다.

이 방법을 수행하는 간단한 방법은 다음과 같습니다 setUpTableForAlbumsFD 방법 이제


dispatch_async(dispatch_get_global_queue(0,0), ^{ 
    [self setUpTableForAlbumsFD]; 
    dispatch_async(dispatch_get_main_queue(), ^{ 
    [albumTable reloadData]; 
    } 
}); 
...

- (void)setUpTableForAlbumsFD { 
    type = @"Albums"; 
    queryAlbums = [MPMediaQuery albumsQuery]; 
    [queryAlbums setGroupingType:MPMediaGroupingAlbum]; 

    mainArrayAlbum = [[NSMutableArray alloc] init]; 

    NSArray *fullArray = [queryAlbums collections]; 
    for (MPMediaItemCollection *collection in fullArray) { 
     item = [collection representativeItem]; 
     NSString *albumName = [item valueForProperty:MPMediaItemPropertyAlbumTitle]; 
     NSString *albumArtist = [item valueForProperty:MPMediaItemPropertyArtist]; 

     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
     NSString *documentsPath = [paths objectAtIndex:0]; 

당신은을 찾는 이들 두 줄을해야 효율성을 위해 for 루프 외부의 NSDocumentDirectory.

 NSString *filePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", albumName]]; 

     UIImage *artwork = [UIImage imageImmediateLoadWithContentsOfFile:filePath]; 

여기서는 UIImage 카테고리 방법이라고 가정합니다.

 Album *album = [[Album alloc] init]; 
     album.albumTitle = albumName; 
     if (album.albumTitle.length > 4) { 
      if ([[NSString stringWithFormat:@"%c%c%c%c", [album.albumTitle characterAtIndex:0], [album.albumTitle characterAtIndex:1], [album.albumTitle characterAtIndex:2], [album.albumTitle characterAtIndex:3]] isEqual: @"The "]) { 

Yikes!album.albumOrderTitle = [album.albumTitle substringFromIndex:4];이 같이 같은 일을 여러 줄을 볼

  } else { 
       album.albumOrderTitle = album.albumTitle; 
      } 
     } else { 
      album.albumOrderTitle = album.albumTitle; 

, 그것은 당신이 그것을 꺼내 수있는 기호의와 다르게 수행 여기 if ([album.albumTitle hasPrefix:@"The "]) {

   album.albumOrderTitle = [album.albumTitle substringWithRange:NSMakeRange(4, album.albumTitle.length-4)]; 

그리고는 할 : 그냥 않습니다. 예를 들어 은 항상이고 album.albumOrderTitlealbumTitle으로 설정 한 다음 albumTitle 길이가 4 이상이고 접두사가 @ "The"인 경우에만 다른 작업을 수행 할 수 있습니다.


 } 
     album.albumArtist = albumArtist; 
     album.albumArtwork = artwork; 
     if (![mainArrayAlbum containsObject:album]) { 
      [mainArrayAlbum addObject:album]; 
     } 
    } 
} 

귀하의 cellForRowAtIndexPath: 유사하게 뒤얽힌된다

MasterCellAlbum *albumCell = [[MasterCellAlbum alloc] init]; 

하는 당신은 UITableView의 세포 재사용 메커니즘을 사용한다.

alphabet = [self alphabet:@"album" withIndex:YES]; 
[albumCell setSelectionStyle:UITableViewCellEditingStyleNone]; 
NSString *alpha = [alphabet objectAtIndex:indexPath.section]; 
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.albumOrderTitle beginswith[c] %@", alpha]; 
[cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 

NSArray *predict = [mainArrayAlbum filteredArrayUsingPredicate:predicate]; 

왜 다시 필터링이 셀을 필요로하는 mainArrayAlbum모든 시간이 있습니까? 마치 항상 alphabet을 잡는 것처럼 보입니다. 즉, 항상 동일한 술어를 정의 할 것입니다. 이는 항상 동일한 predict 배열로 끝날 것임을 의미합니다.

Album *album1 = [predict objectAtIndex:indexPath.row]; 
albumCell.titleLabel.text = album1.albumTitle; 
albumCell.textLabel.text = album1.albumArtist; 
if (album1.albumArtwork) { 
    albumCell.avatarImageView.image = album1.albumArtwork; 
} else { 
    albumCell.avatarImageView.image = [UIImage imageNamed:@"albumArtInvertedLight1.png"]; 
} 

longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(albumLittleMenu:)]; 
[albumCell addGestureRecognizer:longPress]; 
return albumCell; 

그래서, 코드가 일부 개선을 사용할 수있는 몇 가지 분명한 곳이 있습니다. 솔직히, 당신이 가지고있는 문제에 대한 해답은 Bad Idea ™ 인 백그라운드 스레드에서 tableview를 다시로드하려고하기 때문이라고 생각합니다.

+0

감사합니다. 나는 GCD를 사용하는 것에 익숙하지 않다. 대답 해줘서 고마워! 그들이 말하는 것에 대해 알고있는 사람이 내 코드를 분석하는 데 유용합니다! – Giz

+0

그리고 hasPrefix 메서드가 존재하는지 전혀 몰랐습니다. – Giz

+0

@Gizmoloon 좋은 코코아 개발자가되는 75 %는 프레임 워크가 무료로 제공하는 것을 알고 있습니다. 심지어 나는 그들 모두를 알지 못합니다 ... –

관련 문제