等待完成处理程序完成 - Swift

时间:2017-02-15 16:52:02

标签: ios swift closures grand-central-dispatch completionhandler

我正在尝试检查UserNotifications是否已启用,如果不是,我想要发出警报。所以我有一个函数checkAvailability来检查多项内容,包括UserNotification授权状态。

func checkAvailabilty() -> Bool {

    // 
    // other checking
    //

    var isNotificationsEnabled = false
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound], completionHandler: { (granted, error) in

                    if granted {
                        isNotificationsEnabled = true
                    }
                    else {
                        isNotificationsEnabled = false
                    }
                })
            }


    if isNotificationsEnabled {
        return true
    }
    else {
        // Throw alert: Remind user to activate notifications
        return false
    }
}

但是完成处理程序的调用太迟了。函数已经返回false,然后执行colsure中的代码。

我试图将整个语句UNUserNotificationCenter.current().requestAuthorization()放在同步调度队列中,但这并不起作用。

另一种方法是从闭包内部返回,但我不知道如何实现它。

4 个答案:

答案 0 :(得分:13)

不要等待,使用完成处理程序,方便使用枚举:

enum AuthResult {
    case success(Bool), failure(Error)
}

func checkAvailabilty(completion: @escaping (AuthResult) -> ()) {

    //
    // other checking
    //
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound], completionHandler: { (granted, error) in
        if error != nil {
            completion(.failure(error!))
        } else {
            completion(.success(granted))
        }

    })
}

并称之为:

checkAvailabilty { result in
    switch result {
    case .success(let granted) : 
      if granted {
         print("access is granted")
      } else {
         print("access is denied")
      }
    case .failure(let error): print(error)
    }
}

答案 1 :(得分:3)

雅,所以你知道发生了什么是函数在调用完成处理程序之前返回。所以你想要做的是将异步回调传递给checkAvailability函数,这样一旦触发完成处理程序它就会回调。

    func checkAvailabilty(callback: @escaping (Bool) -> Void) {

    //
    // other checking
    //

        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound], completionHandler: { (granted, error) in
            if granted {
                callback(true)
            } else {
                callback(false)
            }
        })
    }
你会像这样调用这个函数......

    checkAvailability(callback: { (isAvailable) -> Void in
        if isAvailable {
            // notifications are available
        } else {
            // present alert
        }
    })

请记住,当您去提示警报时,您可能需要显式地将调用分派给主线程,因为完成处理程序可能会在不同的线程上回调。在这种情况下,您可以调用该函数并显示警报...

    checkAvailability(callback: { (isAvailable) -> Void in
        if isAvailable {
            // notifications are available
        } else {
            DispatchQueue.main.async {
                // present alert
            }
        }
    })

答案 2 :(得分:0)

代码块

if isNotificationsEnabled {
    return true
}
else {
    // Throw alert: Remind user to activate notifications
    return false
}
调用requestAuthorization(options:completionHandler)后立即调用

您应该在完成处理程序中显示警告:

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound], completionHandler: { (granted, error) in
    if !granted {
        // Show alert
    }
})

您的函数checkAvailability不再同步返回Bool,因为对requestAuthorization(options:completionHandler)的调用是异步的。

答案 3 :(得分:0)

另一种方法是在完成处理程序中返回两个参数:

func checkAvailabilty(completion: @escaping (_ granted: Bool, _ error: Error?) -> ()) {
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
        completion(granted, error)
    }
}

使用

checkAvailabilty { granted, error in
    guard error == nil else {
        // An Authorization error has occurred. Present an alert to the user with the error description.
        DispatchQueue.main.async {
            let alert = UIAlertController(title: "Alert", message: error?.localizedDescription ?? "Authorization failed. Unknown error.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            self.present(alert, animated: true)
        }
        return
    }
    if granted {
        print("granted")  // authorization was successful
    } else {
        print("denied")  // present alert from the main thread
        DispatchQueue.main.async {
            let alert = UIAlertController(title: "Attention", message: "The App needs you to turn on notifications !!!", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            self.present(alert, animated: true)
        }
    }
}