加载动画后仅显示按钮功能 (Swift)

Loading Animation Only Showing After Button Function (Swift)

我试图在生成新数组并将其保存到 NSUserDefaults 时显示加载动画。在如下所示的函数中调用了动画函数:

    func getOrCreateCalendar(forYear: Int) -> [DetailedDate] {
       if forYear == date.getDateComponents(todaysDetailDate.date).year && calendar.count > 0 {
           print("forYear == today's year and the current calendar has been RETURNED FROM MEMORY")

           return calendar
       } else {
           let existingCalendar = getExistingCalendar(forYear)

           if existingCalendar != nil {
               return existingCalendar!
           } else {
               SwiftSpinner.show("Generating new calendar for \(forYear)", animated: true)

               let calendar = generateCalendarFor(forYear)

               print("GENERATED NEW calendar for \(forYear)")

               SwiftSpinner.show("Saving calendar", animated: false)

               saveNew(calendar, year: forYear)

               SwiftSpinner.hide()

               return calendar
           }
       }

我正在使用如上所示的开源 SwiftSpinner 动画。 我在整个代码中的多个位置调用此函数(尤其是整个应用程序中的按钮)。

但是,无论何时调用此函数,动画都不会显示,直到整个过程完成。 为什么是这样?如何在生成和保存新内容时显示动画,然后在完成后将其关闭?

尝试使用以下代码在 background-queue 中执行操作:

SwiftSpinner.show("Generating new calendar for \(forYear)", animated: true)
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), {
    let calendar = generateCalendarFor(forYear)

    print("GENERATED NEW calendar for \(forYear)")

    dispatch_async(dispatch_get_main_queue(), {
        SwiftSpinner.show("Saving calendar", animated: false)
    })

    saveNew(calendar, year: forYear)

    dispatch_async(dispatch_get_main_queue(), {
        SwiftSpinner.hide()
        onCompletion(calendar)
    })
})

你在这里做什么:

  • 你创建了一个background-queue
  • 创建日历
  • 从 main-queue 更新 UI (dispatch_async(dispatch_get_main_queue(), { SwiftSpinner.show("Saving calendar", animated: false) }) (main-queue 很重要,因为 UI 只能从 main-queue)
  • 保存日历(在background-queue再次)
  • 调用自定义函数(这里我在 main-queue 中将其命名为 onCompletion,它对日历做了一些事情(替换 return calendar

您应该确保在 dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), { ... }) 被调用并在 onCompletion 中再次启用之前禁用您的 UI-buttons 等,否则用户将能够在您的应用程序时按下某些按钮正在工作(并且可能更改队列使用的一些数据 -> 不好)。

为什么: UI 是从 main-queue 更新的,但通常不会在您调用代码更新后立即更新;如果您阻止 main-queue,您的 UI 将无法更新。所以我们在 background-queue 中完成工作,这样您的 main-queue 就可以更新 UI.

详细: 您调用 dispatch_async(来自 GrandCentralDispatch),它创建一个优先级为 QOS_CLASS_USER_INITIATED(~正常优先级)的新队列。然后它将花括号中的代码传递给这个队列; OS 将在单独的线程中执行队列。 因为 UI 只能从 main-queue 修改,所以我们通过使用 [=16] 将更新 UI (SwiftSpinner.show("Saving calendar", animated: false)) 的代码传递给 main-queue =] 再次。

使用completion-function是必要的,因为code/queue在后台执行并且独立于getOrCreateCalendar;您的功能可能 returns 在队列完成并创建和保存日历之前。