gpt4 book ai didi

ios - 使用 dispatch_async 在后台加载图像

转载 作者:搜寻专家 更新时间:2023-11-01 06:19:02 25 4
gpt4 key购买 nike

我正在尝试在加载图像时更新进度条。我在这里阅读了几个答案,并尝试以多种不同的方式格式化我的代码。我正在尝试阅读图像并更新进度条。然后,将加载的所有图像调用代码来处理它们。我得到的最好结果是一些大部分时间都有效的代码。但是,如果我处理的是拉入大量图像的情况,则会出现奇怪的错误。我认为它会继续运行并在所有图像完全加载之前运行继续代码。当我删除 dispatch_async 时,代码工作正常但进度条不更新。

func imageLocXML(il:String) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
let url:NSURL? = NSURL(string: il)
let data:NSData? = NSData(contentsOfURL: url!)
let image = UIImage(data: data!)
pieceImages.append(image!)
self.numImagesLoaded += 1
self.updateProgressBar()
if self.numImagesLoaded == self.numImagesToLoad {
self.continueLoad()
}
}
}

最佳答案

有很多问题:

  1. 此代码不是线程安全的,因为您在 numImagesLoaded 上存在竞争条件。从理论上讲,这可能会导致多次调用 continueLoad。您可以通过将对此(和其他模型对象)的更新分派(dispatch)回主队列来同步 numImagesLoaded,从而实现线程安全。

  2. 如 DashAndRest 所说,您还必须将 UI 更新分派(dispatch)到主队列。

  3. 当您将其设为异步时,您会在发起大量请求时引入网络超时风险。您可以通过重构代码以使用操作队列而不是调度队列并指定 maxConcurrentOperationCount 来解决此问题。

  4. 正在将图像添加到数组中:

    • 因为这些任务异步运行,所以不能保证它们以任何特定顺序完成,因此数组不会按顺序排列。您应该将图像保存在字典中,这样顺序就不再重要了。

    • 就像 numImagesLoaded 一样,pieceImages 不是线程安全的。

  5. 您使用了很多强制解包,所以如果任何请求失败,这将崩溃。

但是为了解决这个问题,我们必须退后一步,看看调用这个方法的例程。假设您有类似的东西:

var pieceImages = [UIImage()]

func loadAllImages() {
for imageUrl in imageURLs {
imageLocXML(imageUrl)
}
}

func imageLocXML(il:String) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
let url:NSURL? = NSURL(string: il)
let data:NSData? = NSData(contentsOfURL: url!)
let image = UIImage(data: data!)
self.pieceImages.append(image!)
self.numImagesLoaded += 1
self.updateProgressBar()
if self.numImagesLoaded == self.numImagesToLoad {
self.continueLoad()
}
}
}

我建议您将其替换为:

var pieceImages = [String: UIImage]()

func loadAllImages() {
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 4

let completionOperation = NSBlockOperation {
self.continueLoad()
}

for imageURL in imageURLs {
let operation = NSBlockOperation() {
if let url = NSURL(string: imageURL), let data = NSData(contentsOfURL: url), let image = UIImage(data: data) {
NSOperationQueue.mainQueue().addOperationWithBlock {
self.numImagesLoaded += 1
self.pieceImages[imageURL] = image
self.updateProgressBar()
}
}
}

queue.addOperation(operation)
completionOperation.addDependency(operation)
}

NSOperationQueue.mainQueue().addOperation(completionOperation)
}

话虽如此,我认为这里还有更深层次的问题:

  • 你应该像这样提前加载图像吗?我们通常建议延迟加载图像,仅在需要时加载它们。

  • 如果您要将图像加载到这样的结构中,您应该优雅地处理内存压力,在内存不足警告时清除它。然后,您需要优雅地处理当您去检索图像并且由于内存压力而被清除时要做什么(导致您立即回到即时延迟加载模式)。

  • 我们通常建议不要使用同步网络请求(NSData(contentsOfURL:_))。我们通常使用可取消的 NSURLSession,提供更丰富的错误处理等。诚然,这使上述代码更加复杂(可能使我走上异步 NSOperation 的道路子类),但您至少应该了解 contentsOfURL 的限制。

关于ios - 使用 dispatch_async 在后台加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37885623/

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