gpt4 book ai didi

ios - fetchedResultsController.object(位于 : indexPath) operation blocking the main thread

转载 作者:行者123 更新时间:2023-11-30 11:25:39 24 4
gpt4 key购买 nike

我正在创建一个在 Collection View 中显示 gif 的应用程序。我从 GIPHY 公共(public) API 下载 JSON,然后从每个单独的 GIF URL 获取数据,并使用 FLAnimatedImage 将数据存储在 UIImageView 中,然后将其显示在 Collection View 。

我已经 fork 了 FLAnimatedImage pod,并添加了 NSCoding 协议(protocol),以便数据可以在 Core Data 中存档。

在我的 collectionView 中,我使用 fetchedResultsController 来获取填充我的 collectionView 的对象。

由于分页,每次我在 cellForItemAt 中的 collectionView(单列单行)中查看图像的一半时,我的 API 都会调用新图像。

获取新图像的调用是异步的,一旦它返回 fetchRequest 的结果,我就会更新 Collection View 。这不会阻塞主线程。

现在的问题是:一旦我从下载任务中获取数据,我就会将每个 GIF 保存为核心数据堆栈中的 FLAnimatedImage。现在,取消存档会导致为每个图像创建 FLAnimatedImage 并再次运行,这会导致大量 CPU 开销,因为问题是创建 FLAnimatedImage 会占用大量 CPU 资源,因此将其从堆栈中取消存档也是如此。因此,这两个操作都是在分页时对新批处理的图像完成的,最终我的应用程序崩溃了。

速度减慢源于每个 fetchedResultsController.object(at: indexPath) 调用,并且我使用的是 backgroundContext 所以我知道这不是我所在的线程。我认为只是整体 CPU 开销导致了崩溃。但是 fetchedResultsController 不是应该已经将实体从堆栈中拉出吗?为什么要在 fetchedResultsController.object(at: indexPath) 调用中取消存档并创建属性类型(FLAnimatedImage)?

有没有一种方法可以将 FLAnimatedImage 存储在堆栈上,并且每次我使用 fetchedResultsController.object(at: indexPath) 将其从堆栈中拉出时都不需要重新创建它

你能想出一个可能有帮助的策略吗?

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "GSGifCollectionViewCell", for: indexPath) as! GSGifCollectionViewCell

let gifObject:NSManagedObject = self.fetchedResultsController.object(at: indexPath)

gifObject.managedObjectContext?.perform {
let gsGifObject = gifObject as? GSGif
DispatchQueue.main.async {
cell.imageView.animatedImage = gsGifObject?.image
cell.rankLabel.text = "\(gsGifObject?.rank ?? 0)"
}
}


if let totalObjectsForSectionZero = fetchedResultsController.sections?[0].numberOfObjects {
self.checkCurrentIndexPathAndGetMoreGifsIfNeccessary(indexPath: indexPath, totalObjects:totalObjectsForSectionZero)
}


return cell
}

上面我做错了什么吗?

这是我的存档代码:

#import "FLAnimatedImage+NSCoding.h"

@implementation FLAnimatedImage (NSCoding)

static NSString *const kFLAnimatedImageCodingData = @"kFLAnimatedImageCodingData";

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
NSData *data = [aDecoder decodeObjectForKey:kFLAnimatedImageCodingData];
return [self initWithAnimatedGIFData:data];
}

- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:self.data forKey:kFLAnimatedImageCodingData];
}

@end

这会导致主线程阻塞 - [self initWithAnimatedGIFData:data];

最佳答案

首先 - 核心数据不是线程安全的 - 既不能读取也不能写入。所以替换

 gifObject.managedObjectContext?.perform {
let gsGifObject = gifObject as? GSGif
DispatchQueue.main.async {
cell.imageView.animatedImage = gsGifObject?.image
cell.rankLabel.text = "\(gsGifObject?.rank ?? 0)"
}
}

简单地说:

 let gsGifObject = gifObject as? GSGif
cell.imageView.animatedImage = gsGifObject?.image
cell.rankLabel.text = "\(gsGifObject?.rank ?? 0)"

您往返后台线程没有任何帮助,并且违反了核心数据的多线程规则。

下一步 - 在核心数据中存储大量数据通常不是一个好主意 - 因为在大多数关系数据库中这不是一个好主意。反而要么:

a) 将图像存储在文档目录中,并仅将文件路径保存在核心数据中。

b) 创建另一个仅包含数据 blob 的实体,并通过 GSGif 与其建立关系。这样,关系仅在访问时才加载(在核心数据中称为“故障”)。

关于ios - fetchedResultsController.object(位于 : indexPath) operation blocking the main thread,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50770388/

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