我正在使用GCD在后台线程上加载我的UITableView数据,但这样做会混淆我的自定义UITableViewCell中的数据。单元格上的titleLabel和imageView很好,但textLabel(副标题)在每个单元格上都是错误的。当数据加载到主线程上时,这不会发生,并且数据不是来自多个数组,因此我只能猜测它是因为我使用了GCD,我是新手。
首先,我设置了NSOperationQueue ......
- (void)setUpTableForAlbums
{
dispatch_async(dispatch_get_global_queue(0, 0), ^
{
[self setUpTableForAlbumsFD];
dispatch_async(dispatch_get_main_queue(), ^
{
[albumTable reloadData];
});
});
}
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];
}
}
}
相册自定义类只是数据的容器。
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,还是我应该采用其他方式?
答案 0 :(得分:1)
让人惊讶。关于这段代码,我们有很多事情可以说是有趣的。让我们从第一种方法开始:
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
)。文档说:
无法保证完成块的确切执行上下文,但通常是辅助线程。因此,您不应该使用此块来执行任何需要非常特定的执行上下文的工作。
执行此方法的更简单方法是:
dispatch_async(dispatch_get_global_queue(0,0), ^{
[self setUpTableForAlbumsFD];
dispatch_async(dispatch_get_main_queue(), ^{
[albumTable reloadData];
}
});
现在适用于setUpTableForAlbumsFD
方法......
- (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];
为了提高效率,您应该在NSDocumentDirectory
循环之外找到这两行for
。
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 "]) {
糟糕!只需:if ([album.albumTitle hasPrefix:@"The "]) {
album.albumOrderTitle = [album.albumTitle substringWithRange:NSMakeRange(4, album.albumTitle.length-4)];
这里有:album.albumOrderTitle = [album.albumTitle substringFromIndex:4];
} else {
album.albumOrderTitle = album.albumTitle;
}
} else {
album.albumOrderTitle = album.albumTitle;
当你看到多条线路正在做同样的事情时,这是一个标志,你可以把它拉出来并以不同的方式做。例如,您可以始终将album.albumOrderTitle
设置为albumTitle
,然后如果albumTitle长度超过4并且前缀为@“,则只执行不同的操作“。
}
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
,这意味着你总是会定义相同的谓词,这意味着你总是会以相同的{{1}结束数组。
predict
因此,有一些显而易见的地方,您的代码可以使用一些改进。老实说,我认为你遇到的问题的答案是因为你试图在后台线程上重新加载tableview,这是一个坏主意™。