在 UICollectionView 中重新加载数据的正确方法是啥?

Posted

技术标签:

【中文标题】在 UICollectionView 中重新加载数据的正确方法是啥?【英文标题】:What is the correct way to reload data in a UICollectionView?在 UICollectionView 中重新加载数据的正确方法是什么? 【发布时间】:2013-08-16 04:46:40 【问题描述】:

如果我从用户资产库中的相册获取信息,并且他们在我的应用处于后台时添加图片或从中删除。重新加载它们的最佳方法是什么。

目前我有:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(assetsLibraryDidChange:) name:ALAssetsLibraryChangedNotification object:_photoListArray];

要获得初始通知,然后它会调用我的assetLibraryDidChange 方法:

看起来像这样:

- (void)assetsLibraryDidChange:(NSNotification *)note


    //dict nil reload
    if(note.userInfo==nil) 
        [self.CoverView reloadData];
        return;
    

    //dict empty no reload
    if(note.userInfo.count == 0) 
        NSLog(@"empty");
        return;
    

    else 
        [self.CoverView reloadData];
    

虽然我正在考虑删除所有 if 和 else 并且每次都重新加载它。


我要做什么:

我的应用收到通知和实际更新之间似乎存在差距。 Apple 的默认照片应用程序似乎能够在大约 3-4 秒内完成,而我的需要将近 10 秒!有没有更有效的方法来做到这一点?


我继续在所有 if 之前放置一个 nslog,以查看该方法也被调用了多少次。

//Library Updated
- (void)assetsLibraryDidChange:(NSNotification *)note

    NSLog(@"photos updated");

    //dict nil reload
    if(note.userInfo==nil) 
        dispatch_async(dispatch_get_main_queue(), ^
            [self.CoverView reloadData];
            NSLog(@"note: %@", note.userInfo);
            NSLog(@"array: %@", _photoListArray);
            return;
        );
    

    //dict empty no reload
    if(note.userInfo.count == 0) 
        NSLog(@"empty");
        return;
    

    else 
        dispatch_async(dispatch_get_main_queue(), ^
            [self.CoverView reloadData];
            NSLog(@"note2: %@", note.userInfo);
            NSLog(@"array2: %@", _photoListArray);
        );
    


结果如下:

2013-08-16 10:41:51.622 app[180:1803] photos updated
2013-08-16 10:41:51.635 app[180:60b] note2: 
    ALAssetLibraryUpdatedAssetsKey = "(\n    assets-library://asset/asset.JPG?id=CCA17BE2-5633-4FFE-A113-F21E37B9882C&ext=JPG,\n    assets-library://asset/asset.JPG?id=7B05283E-87A5-4CFE-BDBE-7703E311E0DF&ext=JPG,\n    assets-library://asset/asset.JPG?id=5B1E736F-E21E-4400-9679-5DE8215AC09D&ext=JPG\n)";

2013-08-16 10:41:51.638 app[180:60b] array2: (
    "<Media: 0x176b3410>",
    "<Media: 0x176b5b00>",
    "<Media: 0x176b5c90>",
    "<Media: 0x176b7590>",
    "<Media: 0x176b47c0>",
    "<Media: 0x176b7e10>",
    "<Media: 0x176b83b0>",
    "<Media: 0x176b8990>",
    "<Media: 0x176b8f40>",
    "<Media: 0x176b9530>",
    "<Media: 0x176ba160>",
    "<Media: 0x176ba960>",
    "<Media: 0x175794d0>",
    "<Media: 0x175503c0>",
    "<Media: 0x17571f80>",
    "<Media: 0x1756dc20>",
    "<Media: 0x17571060>",
    "<Media: 0x1757b0d0>",
    "<Media: 0x1757b8f0>",
    "<Media: 0x1757bee0>",
    "<Media: 0x1757bcf0>",
    "<Media: 0x1757ca80>",
    "<Media: 0x1757cbd0>"
)
2013-08-16 10:41:51.827 app[180:3e07] photos updated
2013-08-16 10:41:51.831 app[180:3e07] empty
2013-08-16 10:41:51.893 app[180:3e07] photos updated
2013-08-16 10:41:51.897 app[180:3e07] empty
2013-08-16 10:41:52.059 app[180:3e07] photos updated
2013-08-16 10:41:52.074 app[180:3e07] empty
2013-08-16 10:41:52.092 app[180:5117] photos updated
2013-08-16 10:41:52.095 app[180:5117] empty

Media 对象是一个类,我只是用来添加数据并将其与它们一起存储。姓名,分机。不会改变实际图像。

没有调度:

2013-08-16 11:37:53.246 app[296:3d07] photos updated
2013-08-16 11:37:53.255 app[296:3d07] note2: 
    ALAssetLibraryUpdatedAssetsKey = "(\n    assets-library://asset/asset.JPG?id=CCA17BE2-5633-4FFE-A113-F21E37B9882C&ext=JPG,\n    assets-library://asset/asset.PNG?id=D72A00CE-4198-45BE-BCC5-8DEB8419A5C8&ext=PNG,\n    assets-library://asset/asset.JPG?id=5B1E736F-E21E-4400-9679-5DE8215AC09D&ext=JPG\n)";

2013-08-16 11:37:53.260 app[296:3d07] array2: (
    "<Media: 0x176271b0>",
    "<Media: 0x17577920>",
    "<Media: 0x17579c50>",
    "<Media: 0x17579eb0>",
    "<Media: 0x17579e00>",
    "<Media: 0x1757a9b0>",
    "<Media: 0x1757af50>",
    "<Media: 0x1757b540>",
    "<Media: 0x1757baf0>",
    "<Media: 0x1757c0e0>",
    "<Media: 0x17656510>",
    "<Media: 0x176570f0>",
    "<Media: 0x176572b0>",
    "<Media: 0x17657840>",
    "<Media: 0x17657e20>",
    "<Media: 0x17658400>",
    "<Media: 0x176589e0>",
    "<Media: 0x17659270>",
    "<Media: 0x17650470>",
    "<Media: 0x17659380>",
    "<Media: 0x176507a0>",
    "<Media: 0x17650ab0>",
    "<Media: 0x17659cb0>",
    "<Media: 0x1765a340>"
)
2013-08-16 11:37:53.404 app[296:4e17] photos updated
2013-08-16 11:37:53.408 app[296:4e17] empty
2013-08-16 11:37:53.450 app[296:3d07] photos updated
2013-08-16 11:37:53.458 app[296:3d07] empty
2013-08-16 11:37:53.466 app[296:4e17] photos updated
2013-08-16 11:37:53.470 app[296:4e17] empty

【问题讨论】:

通知是否在非主线程上发送?在这种情况下,您必须将 reloadData 发送到主线程。 【参考方案1】:

任何 UI 更改都应该在主线程上完成。尝试:

- (void)assetsLibraryDidChange:(NSNotification *)note


    //dict nil reload
    if(note.userInfo==nil) 
        dispatch_async(dispatch_get_main_queue(), ^
            [self.CoverView reloadData];
            return;
        
    

    //dict empty no reload
    if(note.userInfo.count == 0) 
        NSLog(@"empty");
        return;
    

    else 
        dispatch_async(dispatch_get_main_queue(), ^            
            [self.CoverView reloadData];
        
    

【讨论】:

嘿,我相信你缺少一个 ');'在 if 和 else 语句中。 我坚决修复了速度问题,但它并没有重新加载单元格,也许是 setNeedsLayout? 或者我应该使用batchUpdate吗? 不重新加载应该没问题..但只是为了隔离问题..您可以在每个案例下为 note.userinfo 和_photoListArray 放置一个 nslog 语句并粘贴输出吗? @lostAstronaut hum.. 那么这里的问题是您没有被通知数组中的任何更改.. 您可以重复上述 NSLog 语句但没有dispatch_async(dispatch_get_main_queue(), 代码吗?

以上是关于在 UICollectionView 中重新加载数据的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

UIcollectionView在ios 7中重新加载重叠

如何在不重新加载标题的情况下重新加载 UICollectionView 中的单元格?

在 UICollectionView 中重新加载数据后保持 collectionview 速度

如何在 UICollectionView 中强制重新加载自定义单元格?

在 ios 的 UITableView 或 UICollectionView 中重新加载数据的最佳位置是啥

在 UICollectionView 中使用 reloadData 时如何从重新加载中排除标头