Как обновить NSProgressIndicator?
У меня проблема с NSProgress
, Проблема в том, что NSProgressIndicator
не обновляется во время процесса и показывает только небольшую завершенную часть в конце процесса. LocalizedDescription также отображается только в конце процесса, но завершено на 100%.
Итак, у меня есть класс с одним методом findRepeatsWithProgressReporting
с помощью NSProgress
class TestProgress: NSObject, ProgressReporting
{
let progress: Progress
override init()
{
progress = Progress()
super.init()
}
func findRepeatsWithProgressReporting(stringToSearch: String, minimalLength: Int, maximalLength: Int) -> [String]
{
var arrayOfRepeats = [String]()
progress.totalUnitCount = Int64((minimalLength...maximalLength).count)
for i in minimalLength...maximalLength
{
let arrayOfStrings = stringToSearch.chopString(stringOut: stringToSearch, length: i)
let arrayOfUniqueStrings = Array(Set(arrayOfStrings))
for each in arrayOfUniqueStrings
{
let arrayOfNSRanges = stringToSearch.searchForNSRangesOfStringInString(stringOut: stringToSearch, stringIn: each)
var positions = String()
if arrayOfNSRanges.count > 1
{
for each1 in arrayOfNSRanges
{
let repeatStart = String(each1.location + 1)
let repeatEnd = String(each1.location + each1.length)
positions += "(" + repeatStart + "-" + repeatEnd + ")"
}
let stringToShow = each + " " + positions
arrayOfRepeats.append(stringToShow)
}
}
progress.completedUnitCount += 1
}
return arrayOfRepeats
}
}
Затем в myVewContrloler
У меня есть parentProgress repeatsProgress
имеющий totalUnitCount: 10
и добавил задачу метода findRepeatsWithProgressReporting
как childProgress к parentProgress repeatsProgress
с помощью repeatsProgress.becomeCurrent(withPendingUnitCount: 10)
,
private var progressObservationContext = 0
class myVewContrloler: NSViewController
{
...
var testProgress = TestProgress ()
var repeatsProgress = Progress()
@IBOutlet weak var repeatsSearchProgressBar: NSProgressIndicator!
@IBOutlet weak var repeatsPercentText: NSTextField!
@IBOutlet weak var minimalLength: NSTextField!
@IBOutlet weak var maximalLength: NSTextField!
@IBOutlet var foundRepeats: NSTextView!
@IBAction func actionFindRepeats(_ sender: AnyObject)
{
repeatsProgress = Progress(totalUnitCount: 10)
let options : NSKeyValueObservingOptions = [.new, .old, .initial, .prior]
repeatsProgress.addObserver(self, forKeyPath: "fractionCompleted", options: options, context: &progressObservationContext)
repeatsProgress.addObserver(self, forKeyPath: "localizedDescription", options: options, context: &progressObservationContext)
var arrayOfRepeats = [String]()
repeatsProgress.becomeCurrent(withPendingUnitCount: 10)
arrayOfRepeats = testProgress.findRepeatsWithProgressReporting(stringToSearch: stringToSearch, minimalLength: minimalLength.integerValue, maximalLength: maximalLength.integerValue)
...
repeatsProgress.removeObserver(self, forKeyPath: "fractionCompleted")
repeatsProgress.removeObserver(self, forKeyPath: "localizedDescription")
repeatsProgress.resignCurrent()
}
}
Последняя часть для КВО:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{
guard context == &progressObservationContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
if keyPath == "fractionCompleted"
{
OperationQueue.main.addOperation{
let progress = object as! Progress
self.repeatsSearchProgressBar.doubleValue = progress.fractionCompleted
self.repeatsPercentText.stringValue = progress.localizedDescription
}
}
}
я добавил
print("Observed Something")
внутри
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
{ ...
и то, что я вижу, это два раза печатать "Observed Something"
сразу после запуска и шесть раз в конце, между ними нет печати (как и ожидалось для процесса обновления). В чем может быть причина?
1 ответ
Это похоже на проблему параллелизма. поскольку func actionFindRepeats(_ sender: AnyObject)
работает в основном потоке, он совпадает с обновлениями пользовательского интерфейса, что влияет на NSProgressIndicator
непосредственно.
Посмотрите последний пример этого ответа для более подробной информации об этом:
Вы можете попробовать добавить все содержимое вашей функции actionFindRepeats в этот блок и посмотреть, работает ли она:
DispatchQueue.global().async {
// qos' default value is ´DispatchQoS.QoSClass.default`
}
Ссылка для этого блока: