gpt4 book ai didi

ios - 正确使用 dispatch_async (GCD) 调用

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

我正在尝试从服务器加载一组图像并使用返回的图像更新 UI 并通过淡入淡出动画显示它。它将永远重复。

代码片段:

override func viewDidLoad(animated: Bool) {
super.viewDidLoad(animated)
self.loadImages()
}


func loadImages(){

var urlImage:UIImage?

//self.array_images contains preloaded images (not UIImage) objects which i get from different api call.
if imageCount >= self.array_images!.count{
imageCount = 0
}

var img = self.array_images[imageCount]
var url = NSURL(string: img.url!)
var data = NSData(contentsOfURL: url!)
if (data != nil){
urlImage = UIImage(data: data!)

UIView.transitionWithView(self.imageView_Promotion, duration: 1.2, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
println("Begin Animation")
self.imageView_Promotion.image = realImage

}, completion:{ finished in
println("Completed")
self.imageCount++
self.loadImages() //another issue: it calls the function more than couple of times
})

}
}else{
var image:UIImage = UIImage(named: "test_Image.jpg")!
imageView_Promotion.image = image
}

上面那个挂了UI。我已尝试在 dispatch_async 中调用 loadImages 并在 dispatch_main 队列中调用动画,但问题仍然存在。

let priority = DISPATCH_QUEUE_PRIORITY_BACKGROUND
dispatch_async(dispatch_get_global_queue(priority, 0)) {
self.loadImages()
}

dispatch_async(dispatch_get_main_queue(),{
//UIView animation
})

处理这个问题的正确方法是什么。

谢谢

最佳答案

线程安全问题

基本上,UIKit API 不是线程安全的。这意味着 UIKit API 应该只从主线程(主队列)调用。但是,实际上,也有一些异常(exception)。例如,UIImage +data: 是线程安全的 API。

您的代码包含一些不安全的调用。

UIView.transitionWithView(self.imageView_Promotion, duration: 1.2, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {

我不认为 UIView.transitionWithView 是线程安全的。

var image:UIImage = UIImage(named: "test_Image.jpg")!

UIImage +named: 不是线程安全的,它使用全局缓存等等。根据UIImage init(named:) Discussion .

You can not assume that this method is thread safe.

阻塞主线程

如果线程安全问题得到解决,它会阻塞主线程。

您的代码调用 loadImages 方法,该方法从 UIView.transitionWithView 的完成 block 中从服务器下载图像或从文件系统加载图像。 UIView.transitionWithView 应该从主线程调用,所以完成 block 也将从主线程调用。这意味着在主线程上下载或加载图像。它阻塞了主线程。

示例代码

因此,loadImages 应该像下面这样。

Swift Playground 代码:

import UIKit
import XCPlayground

func loadImage(file:String) -> UIImage {
let path = NSBundle.mainBundle().pathForResource(file, ofType: "")
let data = NSData(contentsOfFile: path!)
let image = UIImage(data: data!)
return image!
}

var index = 0
let files = ["image0.png", "image1.png", "image2.png"]
let placementImage = loadImage(files[0])
let view = UIImageView(image:placementImage)

//加载图片函数

func loadImages() {
let priority = DISPATCH_QUEUE_PRIORITY_BACKGROUND
dispatch_async(dispatch_get_global_queue(priority, 0)) {
/*
* This block will be invoked on the background thread
* Load an image on the background thread
* Don't use non-background-thread-safe APIs like UIImage +named:
*/
if index >= files.count {
index = 0
}
var file = files[index++]
let image = loadImage(file)

dispatch_async(dispatch_get_main_queue()) {
/*
* This block will be invoked on the main thread
* It is safe to call any UIKit APIs
*/
UIView.transitionWithView(view, duration: 1.2, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
/*
* This block will be invoked on the main thread
* It is safe to call any UIKit APIs
*/
view.image = image
}, completion:{ finished in
/*
* This block will be invoked on the main thread
* It is safe to call any UIKit APIs
*/
loadImages()
})
}
}
}

//从主线程调用loadImages()

XCPShowView("image", view)
loadImages()
XCPSetExecutionShouldContinueIndefinitely()

关于ios - 正确使用 dispatch_async (GCD) 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27621213/

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