从Web API检索数据时未显示进度条

时间:2017-03-27 22:50:12

标签: ios swift progress-bar uiprogressview

Swift 3 / Xcode 8 / ios 10

我有一个从几个api端点获取大量数据的方法。我挑选出我想要保留的位,然后格式化并将该数据打印到文本文件中。

当应用启动时,它会检查文本文件是否为空。如果为空,则运行API请求并相应地填充文本文件。到现在为止还挺好。这一切都按预期工作。

我现在想要通过进度条向用户显示正在检索的数据的进度。这是我陷入困境的地方。我似乎无法在数据检索之前和期间显示进度条。它仅在数据检索完成后显示 - 并且同样表示。通过协议方法中的一些打印语句,我可以看到进度条似乎正在更新 - 它只是在我想要它时不会发生到进度条的segue。

上述说明涉及3个类别:

  1. MasterVC - 检查文本文件并在必要时转移到ProgressBar。在调用performSegue到ProgressBar之后立即通过GetData.start()启动API调用。
  2. ProgressBar - 显示进度条并从GetData接收更新。
  3. GetData - 包含从API获取数据的方法。
  4. 在MasterVC的viewDidAppear中,下面的代码显示了第一个代码块:

        if fileSize == 0{
    
            //SHOW PROGRESS OVERLAY AND RETRIEVE API DATA
            performSegue(withIdentifier: "toProgressBarOverlay", sender: self)
    
            GetData.start() //IF THIS IS ACTIVE, DATA IS RETRIEVED BUT PROGRESS BAR APPEARS AT THE END.
    
        }
    

    此后的任何代码只有在通过API调用填充文本文件后才会运行。我通过使用API​​调用方法中包含的信号量来完成此操作。相反,我将GetData.start()放在ProgressBar的viewDidAppear中,我在本节中得到的与变量/数组等相关的错误是空的。

    从谷歌搜索和搜索SO,我得到的印象是进度条的后期显示只与每个周期结束时的视图更新有关,虽然我先调用performSegue,但它只发生最后,在类的其余代码迭代完毕之后。

    如何使此进度条按预期显示?

    编辑1:

    好的,所以我设法让进度条现在出现在API调用的开头。但遗憾的是,进度条没有正确更新。但是,更新仍在控制台中正确报告。进度条显示默认的起始值,然后一旦API调用完成,进度条突然射到100%,没有中间值。使用dispatchQueue.main.async / sync仍然不起作用。以下是我所做的更改:

    上面的代码部分(在MasterVC中)现在如下所示:

    //FETCH MP INFO AND POPULATE MPDATA.TXT.
        if fileSize == 0{
    
            //SHOW PROGRESS OVERLAY AND RETRIEVE API DATA
            performSegue(withIdentifier: "toProgressBarOverlay", sender: self)
    
        }
    

    此后的所有代码(处理填充的文本文件)已移至其自己的方法(称为processTextFile)。

    因此,当应用程序启动时,它会检查一个空文件,如果找到那么多,则转到ProgressBar。 ProgressBar现在还包含一个对MasterVC的新引用(称为masterVcReference),它在prepareForSegue期间设置。

    ProgressBar现在使用以下命令启动API调用:

    GetData.start(masterVc: masterVcReference!)
    

    检索完所有数据并将其写入文件后,GetData使用masterVcReference来调用processTextFile。

    实际的协议方法如下:

    func updateProgressBar(message: String, percentComplete: Float) {
    
        print("Progress: \(percentComplete)%") << this is being reported correctly.
    
        ProgressBar?.setProgress(percentComplete, animated: true)
        ProgressBarMessageField.text = message
    
        if percentComplete == 100{
            //dismiss(animated: true, completion: nil)
        }
    }
    

    如果我放置“ProgressBar?.setProgress(percentComplete,animated:true)”和         dispatchQueue.main.async / sync块中的“ProgressBarMessageField.text = message”,没有区别。

    目前,除了进度条没有按预期更新外,该应用程序应该正常工作。

    编辑2:

    好的,所以使用DispatchQueue.global(qos:.userInteractive).async,而不是dispatchQueue.main.async来更新进度条已经有了很大的不同。进度条更新,排序。如果我很幸运的话,进度条应该通过的649个更新(来自处理的649项数据),它只会更新1,2或3次。此外,应用程序的每次运行之间的更新频率都不相同。

    编辑3:

    确定 - 结果是dispatchQueue.main.async一直在工作,但似乎是排队所有更新并在最后执行所有操作而不是执行每个协议方法调用。混乱占主导地位。

    最后解决了!

    我正在使用信号量来确保以正确的顺序处理来自API调用的数据。解决方案是在调用委托方法之前放置“semaphore.signal()”语句。最初,委托调用位于“let semaphore = DispatchSemaphore(value:0)”和“semaphore.signal()”之间。不知怎的(我还不明白),这导致UI更新排队,直到所有API数据都处理完毕才执行。

    瞧!

1 个答案:

答案 0 :(得分:0)

我正在使用信号量来确保以正确的顺序处理来自API调用的数据。解决方案是在调用委托方法之前放置“semaphore.signal()”语句。最初,委托调用位于“let semaphore = DispatchSemaphore(value:0)”和“semaphore.signal()”之间。不知怎的(我还不明白),这导致UI更新排队,直到所有API数据都处理完毕才执行。