为什么不在主线程上加载图像?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么不在主线程上加载图像?相关的知识,希望对你有一定的参考价值。

我正在使用此代码从URL加载图像:Loading/Downloading image from URL on Swift。这工作正常。

我将代码从viewcontroller中取出并放入一个类中。现在,只有在我单步执行代码时才会加载图像。我猜这与运行正常的代码有关,但是一切都在图像完全从网上下载之前完成。

我错过了什么,所以代码等待图像而没有阻止在viewcontroller中执行的任何其他代码?

class MyClass:NSObject {

private var myImage:UIImage = UIImage()

func getMyImage() -> UIImage {
    if let url = URL(string: self.myUrl) {
            self.myImage = self.downloadImage(url: url)
    }
    return self.myImage
}

func getDataFromUrl(url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
    URLSession.shared.dataTask(with: url) { data, response, error in
        completion(data, response, error)
        }.resume()
}

func downloadImage(url: URL) {
    print("Download Started")
    getDataFromUrl(url: url) { data, response, error in
        guard let data = data, error == nil else { return }
        print(response?.suggestedFilename ?? url.lastPathComponent)
        print("Download Finished")
        DispatchQueue.main.async() {
            self.myImage = UIImage(data: data)!
        }
    }
}
}

//在ViewController中

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    DispatchQueue.main.async() {
        self.theImageView.image = self.myClass?.getImage()
    }
}
答案

异步回调完成后,您必须设置imageView图像。

class MyClass: NSObject {
    // async function
    func getMyImage(completion: @escaping (UIImage?) -> Void) {
        // if the url is not available, completion with null
        guard let url = URL(string: self.myUrl) else { 
            completion(nil)
            return 
        }

        getDataFromUrl(url: url) { data, response, error in
            // if something goes wrong, completion with null
            guard let data = data, error == nil else { 
                completion(nil)
                return 
            }
            print(response?.suggestedFilename ?? url.lastPathComponent)
            print("Download Finished")
            completion(UIImage(data: data)!)
        }
    }
}

// in ViewController
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    getImage { image in 
        // async function will get called when image is ready
        DispatchQueue.main.async() { // set up your view in main thread
            self.theImageView.image = image
        }
    }
}

以上是关于为什么不在主线程上加载图像?的主要内容,如果未能解决你的问题,请参考以下文章

从主线程的资产目录中加载图像?

如何将图像视图从改造加载的片段传递给子片段?

android从网络上异步加载图像

SwiftUI 列表 - 远程图像加载 = 图像闪烁(重新加载)

CreateProcess 不在主线程中

图像加载/缓存主线程