问题
I'm decoding several gigabytes of JSON encoded data like this
let decoder = JSONDecoder()
let table = try decoder.decode([LogRow].self, from: content!)
where content
is plain text. Now, this operation can take several minutes, depending on the size of content
, and I'd like to show some kind of progress. This is a command line program, so even a periodic update on the length of table
would be enough. The problem is that I don't see anything like a callback or something like that. I tried with a rather awkward Timer
like this
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()
but that only runs once -- is it because the decoder blocks the main thread and I'm running the timer in the same thread? I'm a bit of a noob with the GCD so I'm not sure how to go about using a DispatchQueue
for this.
Any ideas?
回答1:
Then can declare your timer like:
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()
}
which means you want to trigger the updateUI
action every second. Then you start to decode
in a background thread and wait until done before invalidate your timer.
var totalDuration: Int = 0
@objc func updateUI () {
self.currentDuration += 1
print("------------> \(self.currentDuration)")
}
@objc func decode () {
table = try decoder?.decode([LogRow].self, from: content!)
}
I added a currentDuration
variable which could be used in your progressBar. But you must know the total duration if you need to show a percentage to your user.
来源:https://stackoverflow.com/questions/46809851/update-a-progress-bar-while-jsondecoder-is-decoding-a-huge-object-in-swift