【问题标题】:How to update the NSProgressIndicator?如何更新 NSProgressIndicator?
【发布时间】:2017-03-21 00:05:15
【问题描述】:

NSProgress 有问题。问题是NSProgressIndicator 在此过程中没有更新,并且在过程结束时仅显示一小部分已完成的部分。本地化描述也仅在流程结束时显示,但已 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 repeatsProgresstotalUnitCount: 10,并使用 repeatsProgress.becomeCurrent(withPendingUnitCount: 10) 将方法 findRepeatsWithProgressReporting 的任务作为 childProgress 添加到 parentProgress repeatsProgress

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()
    }
}

最后一部分是KVO:

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",在结束时打印六次,中间没有打印(因为它预期用于更新过程)。可能是什么原因?

【问题讨论】:

    标签: macos swift3 nsprogressindicator nsprogress


    【解决方案1】:

    这似乎是一个并发问题。由于func actionFindRepeats(_ sender: AnyObject)在主线程中运行,它与UI更新同步,直接影响NSProgressIndicator

    有关详细信息,请参阅该答案的最后一个示例:

    您可以尝试将您的 actionFindRepeats 函数的所有内容添加到该块中,看看它是否有效:

    DispatchQueue.global().async {
        // qos' default value is ´DispatchQoS.QoSClass.default`
    }
    

    该块的参考:

    【讨论】:

    • 感谢您的建议!我只为上述任务制作了一个测试项目,搜索带有进度报告的字符串中的重复项。一切都在 AppDelegate 中完成。我已经按照您的建议添加了 DispatchQueue.global().async,现在在这个项目中,我看到完成 NSProgressIndicator 并且在流程结束时 100% 完成了本地化描述。在主项目中,我为相同的任务有单独的控制器,但仍然是不完整的 NSProgressIndicator。而且,在这两个项目中,我都没有更新 NSProgressIndicator,没有中间百分比。
    • 现在在两个项目中,经过我所做的更改后,我在测试项目中也有以下警告:2017-03-24 19:39:55.202 Test2[3926:127626] 未提交的 CATransaction。在调试环境中设置 CA_DEBUG_TRANSACTIONS=1。 CoreAnimation:警告,删除了未提交 CATransaction 的线程;在环境中设置 CA_DEBUG_TRANSACTIONS=1 以记录回溯。
    • 我看到你的建议是解决问题的正确方法,所以再次感谢,我接受你的回答。
    猜你喜欢
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多