Ios 如何在另一个函数中执行任务,并随着任务的进展从那里更新UI?
这是我的主viewcontroller中的代码Ios 如何在另一个函数中执行任务,并随着任务的进展从那里更新UI?,ios,swift,multithreading,asynchronous,Ios,Swift,Multithreading,Asynchronous,这是我的主viewcontroller中的代码 import UIKit class ViewController: UIViewController { @IBOutlet weak var progressUI: UIProgressView! override func viewDidLoad() { super.viewDidLoad() simulateDownload() } override func
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
}
}
导入UIKit
类ViewController:UIViewController
{
@IBMProgressUI:UIProgressView!
重写func viewDidLoad()
{
super.viewDidLoad()
模拟下载()
}
重写函数didReceiveMemoryWarning()
{
超级。我收到了记忆警告()
}
func simulateDownload()->数组
{
变量结果=[Tweak]()
让searchQuery=“激活器”
让url=url(字符串:https://cydia.saurik.com/api/macciti?query=“+搜索查询)
让urlData=try?Data(contentsOf:url!)
变量i=0
让jsonResult=try?JSONSerialization.jsonObject(带:urlData!,选项:JSONSerialization.ReadingOptions.mutableContainers)作为![String:Any]
让resultTweaks=jsonResult?[“results”]作为!数组
用于在resultTweaks中进行调整
{
i+=1
让进度=(浮动(i)/浮动(resulttwawaks.count))
追加(调整(调整数据:调整为![String:String]))
DispatchQueue.main.async()
{
self.progressUI.progress=进度
}
打印(进度)
}
打印(“完成”)
返回结果
}
}
这是我的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!)!
}
}
<代码>导入基础
导入UIKit
类调整
{
变量名称、id、节、描述、版本、thumbURL:String
变量图标:UIImage
init(数据:字典)
{
self.name=tweakdata[“显示”]为!字符串
self.id=tweakdata[“name”]作为!字符串
self.section=tweakdata[“section”]作为!字符串
self.description=tweakdata[“summary”]作为!字符串
self.version=tweakdata[“version”]作为!字符串
self.thumbURL=”https://cydia.saurik.com/icon@2x/“+self.id+”.png”
//加载图标
让imgURL=URL(字符串:self.thumbURL)
让imgData=try?数据(contentsOf:imgURL!)
self.icon=UIImage(数据:imgData!)!
}
}
我想在创建每个调整实例时更新UIProgressView(progressUI)。但UI仅在函数返回后更新。有人能给我解释一下所有这些工作以及线程应该如何完成吗?
我不熟悉快速异步编程 for循环已经在主线程上,因此它将阻止任何UI更新,这不仅会禁用进度条更新,还会禁用用户交互 任何长时间运行的任务都应该在后台线程上运行。幸运的是,这在Swift中很简单 由于您已经在更新“进度”视图,类似这样的操作将起作用:
DispatchQueue.global(qos: .background).async {
simulateDownload()
}
而不是在viewDidLoad
请注意,使用这种方法,不能直接从主线程使用函数的返回值
您应该做的是从闭包中提供值,如下所示:
func simulateDownload(@escaping closure: (_ result:Array<Tweak>) -> ()) {
DispatchQueue.global(qos: .background).async {
[...]
DispatchQueue.main.async{
closure(results)
}
}
}
simulateDownload(closure: {
results in
[...]
})
这只是表面现象,如果您想了解更多有关Swift中闭包的信息,我建议您阅读以下内容:非常感谢。成功了。如何确定块是否在主线程中?和
DispatchQueue.global(qos:.background).async{}
使块中给定的内容在不同的线程中运行?要检查是否在主线程中,只需检查thread.isMainThread
,是的,块在不同的线程中运行。