gpt4 book ai didi

ios - 使用 GCD 时 UITableViewCell 数据被混淆

转载 作者:行者123 更新时间:2023-11-29 13:13:44 25 4
gpt4 key购买 nike

我正在使用 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];
}

}
}

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,或者我应该使用其他方法吗?

最佳答案

哎呀。关于这段代码,我们可以说,有很多有趣的地方。让我们从第一种方法开始:

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 的地方)。文档说:

The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context.

执行此方法的更简单方法是:

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];

为了提高效率,您应该在 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 "]) {

哎呀!只需执行: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 时才做一些不同的事情它有一个前缀@"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,这意味着你总是会定义相同的谓词,这意味着你总是会得到相同的结果预测数组。

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;

因此,您的代码有一些明显的地方需要改进。老实说,我认为您遇到的问题的答案是因为您试图在后台线程上重新加载 tableview,这是一个坏主意™。

关于ios - 使用 GCD 时 UITableViewCell 数据被混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16428890/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com