iOS-更新UITableViewCell信息而不重新加载行?

Chr*_*ian 5 key-value key-value-observing uitableview ios

假设您有一个UITableView显示file元数据列表,并且您希望以自定义的形式显示download_progress每个文件UILabel的内容UITableViewCell.(这是一个任意长的列表 - 因此将重用动态单元格).

如果你想更新标签而不打电话,reloadData或者reloadRowsAtIndexPaths你怎么做?

对于那些想知道的人 - 我不想调用任何一种reload...方法,因为没有必要为每个百分点更新重新加载整个单元格download_progress.

我遇到的唯一解决方案是:

  • 添加单元格作为一个键值观察员filedownload_progress.

  • cellForRowAtIndexPath...直接调用以获取标签并更改其文本.

然而,KVO通常不是一个有趣的api - 当你在混合中添加单元重用时更是如此.cellForRowAtIndexPath每次添加百分点时直接调用都会感觉很脏.

那么,有哪些可能的解决方案?任何帮助,将不胜感激.

谢谢.

Chr*_*ian 2

作为道格回应的必然结果,这就是我最终得到的结果:

每个file都有一个唯一的标识符,所以我让它负责发布有关其属性更新的通知(想想 KVO,但没有麻烦):

我做了一个FileNotificationType枚举(即FileNotificationTypeDownloadTriggered, 和FileNotificationTypeDownloadProgress)。然后我会将进度与 一起NSNotification发送到 的 中。userInfo NSDictionaryFileNotificationType

- (void)postNotificationWithType:(FileNotificationType)type andAttributes:(NSDictionary *)attributes
{
    NSString *unique_notification_id = <FILE UNIQUE ID>;

    NSMutableDictionary *mutable_attributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
    [mutable_attributes setObject:@(type) forKey:@"type"];

    NSDictionary *user_info = [NSDictionary dictionaryWithDictionary:mutable_attributes];

    dispatch_async(dispatch_get_main_queue(), ^{
    [[NSNotificationCenter defaultCenter] postNotificationName:unique_notification_id object:nil userInfo:user_info];
    });
}
Run Code Online (Sandbox Code Playgroud)

file对象还有一个方法来枚举它可以发送的通知类型:

- (NSArray *)notificationIdentifiers
{
    NSString *progress_id = <FILE UNIQUE ID + FILENOTIFICATIONTYPE>;
    NSString *status_id = <FILE UNIQUE ID + FILENOTIFICATIONTYPE>
    NSString *triggered_id = <FILE UNIQUE ID + FILENOTIFICATIONTYPE>

    NSArray *identifiers = @[progress_id, status_id, triggered_id];
    return identifiers;
}
Run Code Online (Sandbox Code Playgroud)

因此,当您更新其他地方的属性时file,只需执行以下操作:

NSDictionary *attributes = @{@"download_progress" : @(<PROGRESS_INTEGER>)};
[file_instance postNotificationWithType:FileNotificationTypeDownloadProgress andAttributes:attributes];
Run Code Online (Sandbox Code Playgroud)

在接收端,我的表视图委托实现了这些方法来添加/删除我的自定义UITableViewCells作为这些通知的观察者:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    File *file = [modelObject getFileAtIndex:indexPath.row];
    for (NSString *notification_id in file.notificationIdentifiers)
    {
        [[NSNotificationCenter defaultCenter] addObserver:cell selector:@selector(receiveFileNotification:) name:notification_id object:nil];
    }
}

- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [[NSNotificationCenter defaultCenter] removeObserver:cell];
}
Run Code Online (Sandbox Code Playgroud)

最后,自定义UITableViewCell必须实现该receiveFileNotification:方法:

 - (void)receiveFileNotification:(NSNotification *)notification
{
    FileNotificationType type = (FileNotificationType)[notification.userInfo[@"type"] integerValue];

    // Access updated property info with: [notification.userInfo valueForKey:@"<Your key here>"]

    switch (type)
    {
        case FileNotificationTypeDownloadProgress:
        {
            // Do something with the progress
            break;
        }
        case FileNotificationTypeDownloadStatus:
        {
            // Do something with the status
            break;
        }
        case FSEpisodeNotificationTypeDownloadTriggered:
        {
            // Do something if the download is triggered
            break;
        }
        default:
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助那些想要更新表格视图单元格而无需重新加载它们的人!相对于键值观察的好处是,如果在File单元格仍在观察的情况下释放对象,您不会遇到问题。我也不必打电话cellForRow...

享受!