Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在JSONDecoder用Swift解码巨大对象时更新进度条_Swift_Timer_Progress_Swift4_Codable - Fatal编程技术网

在JSONDecoder用Swift解码巨大对象时更新进度条

在JSONDecoder用Swift解码巨大对象时更新进度条,swift,timer,progress,swift4,codable,Swift,Timer,Progress,Swift4,Codable,我正在解码几GB的JSON编码数据,如下所示 let decoder = JSONDecoder() let table = try decoder.decode([LogRow].self, from: content!) var table: [LogRow]? = [] let timer = Timer(fire: Date(), interval: 1.0, repeats: true) { t in print("\(table?.count ?? 0) rows pars

我正在解码几GB的JSON编码数据,如下所示

let decoder = JSONDecoder()
let table = try decoder.decode([LogRow].self, from: content!)
var table: [LogRow]? = []
let timer = Timer(fire: Date(), interval: 1.0, repeats: true) { t in
    print("\(table?.count ?? 0) rows parsed.")
}
timer.fire()
table = try decoder.decode([LogRow].self, from: content!)
timer.invalidate()
其中,
内容
为纯文本。现在,这个操作可能需要几分钟,具体取决于
内容的大小,我想展示一些进展。这是一个命令行程序,因此即使定期更新
表的长度也足够了。问题是,我没有看到类似回调之类的东西。我试着用一个相当笨拙的
计时器
,就像这样

let decoder = JSONDecoder()
let table = try decoder.decode([LogRow].self, from: content!)
var table: [LogRow]? = []
let timer = Timer(fire: Date(), interval: 1.0, repeats: true) { t in
    print("\(table?.count ?? 0) rows parsed.")
}
timer.fire()
table = try decoder.decode([LogRow].self, from: content!)
timer.invalidate()
但它只运行一次——是因为解码器阻塞了主线程,而我在同一线程中运行计时器吗?我对GCD有点不在行,所以我不知道如何使用
DispatchQueue


有什么想法吗?

然后可以声明您的计时器如下:

    let timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateUI), userInfo: nil, repeats: true)
    DispatchQueue.global(qos: .background).async {
        self.perform(#selector(self.decode), on: Thread.current, with: nil, waitUntilDone: true)
        timer.invalidate()
    }
这意味着您希望每秒触发
updateUI
操作。然后在后台线程中开始
解码
,并等待完成,然后使计时器无效

var totalDuration: Int = 0

@objc func updateUI () {
    self.currentDuration += 1
    print("------------> \(self.currentDuration)")
}

@objc func decode () {
    table = try decoder?.decode([LogRow].self, from: content!)
}

我添加了一个
currentDuration
变量,可以在progressBar中使用。但如果需要向用户显示百分比,则必须知道总持续时间

currentDuration在您不知道检查它时有什么好处?它与表的长度一样好,因此对于我的用例来说已经足够了。但是表的长度需要与解析整个json所需的总时间直接相关。但在这种情况下,我不明白你怎么知道需要多长时间。(也就是说,它需要基于与时间相反的其他东西)但我从来没有说过我想要显示百分比或预计到达时间之类的东西,所以这两个量中的任何一个对我来说都是完美的。事实上,我大致知道表中会有多少行,因此即使显示我每秒钟的位置也是一个巨大的改进。这就是我理解您的问题的方式:)要在CLI中执行异步任务(如
计时器),您需要一个运行循环。我有点假设重复
计时器
会有自己的内部运行循环。那么,您建议的解决方案是什么?不,您使用的计时器API需要显式地将计时器附加到运行循环,并且
scheduled…
API假定存在运行循环。但是CLI在默认情况下没有运行循环。请谷歌命令行界面runloop。有几种解决方案。您的
LogRow
类型有多复杂?如果您提供一个自定义的
可解码的
实现,您可以实现一个非常细粒度的进度跟踪器。它非常复杂,我提供了一个非常详细的自定义
可解码的
。你建议我如何利用这一点?(感谢您的编辑,我一定是在复制粘贴时错过了它们)