ios - 如何在另一个函数中执行任务并随着任务的进行从那里更新 UI?

标签 ios swift multithreading asynchronous

这是我的主视图 Controller 的代码

import UIKit

class ViewController: UIViewController
{

    @IBOutlet weak var progressUI: UIProgressView!
    override func viewDidLoad()
    {
        super.viewDidLoad()
        simulateDownload()
    }



    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()

    }

    func simulateDownload() -> Array<Tweak>
    {
        var results = [Tweak]()
        let searchQuery = "activator"
        let url = URL(string: "https://cydia.saurik.com/api/macciti?query=" + searchQuery)
        let urlData = try? Data(contentsOf: url!)
        var i = 0
        let jsonResult = try? JSONSerialization.jsonObject(with: urlData!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: Any]
        let resultTweaks = jsonResult?["results"] as! Array<Any>
        for tweak in resultTweaks
        {
            i += 1
            let progress = (Float(i) / Float(resultTweaks.count))
            results.append(Tweak(tweakdata: tweak as! [String: String]))
            DispatchQueue.main.async()
            {
                self.progressUI.progress = progress

            }
            print(progress)

        }
        print("done")
        return results
    }


}

这是我的 Tweak 类,当您创建它的实例时会在其中下载图标

import Foundation
import UIKit

class Tweak
{
    var name, id, section, description, version, thumbURL: String
    var icon: UIImage
    init(tweakdata: Dictionary<String, Any>)
    {
        self.name = tweakdata["display"] as! String
        self.id = tweakdata["name"] as! String
        self.section = tweakdata["section"] as! String
        self.description = tweakdata["summary"] as! String
        self.version = tweakdata["version"] as! String
        self.thumbURL = "https://cydia.saurik.com/icon@2x/" + self.id + ".png"
        //load icon
        let imgURL = URL(string: self.thumbURL)
        let imgData = try? Data(contentsOf: imgURL!)
        self.icon = UIImage(data: imgData!)!

    }
}

我想在创建每个 Tweak 实例时更新 UIProgressView(progressUI)。但 UI 仅在函数返回后更新。有人可以向我解释所有这些工作原理以及线程应该如何完成吗? 我是快速和异步编程的新手。

最佳答案

您的 for 循环已经在主线程上,因此它将阻止任何 UI 更新,这不仅会禁用进度条更新,还会禁用用户交互。

任何长时间运行的任务都应该在后台线程上运行。幸运的是,这在 Swift 中很容易。

因为您已经在更新进度 View ,所以这样的事情会起作用:

DispatchQueue.global(qos: .background).async {
    simulateDownload()
}

而不是只在viewDidLoad中调用simulateDownload

请注意,使用这种方法,您不能直接从主线程使用函数的返回值。

您应该做的是从闭包中提供值,如下所示:

func simulateDownload(@escaping closure: (_ result:Array<Tweak>) -> ()) {
    DispatchQueue.global(qos: .background).async {
        [...]
        DispatchQueue.main.async{
            closure(results)
        }
    }
}

并像这样使用它:

simulateDownload(closure: {
    results in
    [...]
})

这只是触及表面,如果您想了解更多有关 Swift 中的闭包的信息,我建议您阅读:https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID94

关于ios - 如何在另一个函数中执行任务并随着任务的进行从那里更新 UI?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45118616/

相关文章:

ios - 是否可以为不同的尺寸类别设置不同的表格 View 单元格行高?

iphone - 带有自定义标题的 UIBarButtonItem

jquery - 如何在开始转换之前阻止移动 Safari 暂停

Swift-添加两个UI编号然后在标签中输出

objective-c - 从 Swift 中的非泛型函数调用泛型函数

java - 在同步方法中发布后,普通方法中的非不可变类可见性

c++ - 带有信号量的线程安全单例问题

c# - 目标 Sharpie 缺少大部分 API

ios - 如何处理从 JSON 返回的 Null

java - 为什么 Java 使用线程抽象而不是协程?