如果重要的话,这个应用程序是一个4.2应用程序,但正在升级到5.0与新的功能,包括这个。
作为对可用内容APN的响应,在触发消息给第三方之前,我需要将本地设备数据与远程数据结合起来。在前台,这个过程工作,但在后台,它似乎冻结,直到应用程序在前景。
我想用一个DispatchQueue来解决这个问题--这让我走得更远了,但它仍然没有完全解决。
当我收到我的APN时,我确保它看起来是正确的(这是一个内容-avaialbe通知,并且有一个类别),然后启动loadPrediction。
// Tells the app that a remote notification arrived that indicates there is data to be fetched.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler:
@escaping (UIBackgroundFetchResult) -> Void) {
guard let aps = userInfo["aps"] as? [String: AnyObject] else {
completionHandler(.failed)
return
}
if aps["content-available"] as? Int == 1 {
guard let category = aps["category"] as? String else {
print("on didReceiveRemoteNotification - did not receive payload with category")
print(String(describing: userInfo))
return
}
switch category {
case APNCATEGORIES.PREDICTION.rawValue:
DataModel.shared.loadPredictions() {
completionHandler(.newData)
}
break
default:
print("on didReceiveRemoteNotification - received unknown category '\(category)'")
completionHandler(.failed)
}
} else {
print("on didReceiveRemoteNotification - did not receive content-available in APN")
print(String(describing: aps))
completionHandler(.noData)
}
}在loadPredictions中,我从后端请求两段数据。编辑: I've read that you might want to start a different queue for each POST request,所以我已经将下一个代码块修改为它的当前形式,而不仅仅是一个队列:
/** load prediction data for notification scheduling */
func loadPredictions(_ callback: @escaping () -> Void) {
print("loading predictions")
let queue = DispatchQueue(label: "loadingPredictions", qos: .utility, attributes: .concurrent)
queue.sync { [weak self] in
print("loading predictions - in async task, about to getPredictionsDataFromFirestore")
self?.getPredictionsDataFromFirestore() { [weak self] in
print("getting Predictions Data from Firestore")
if let error = $2 {
NotificationCenter.default.post(Notification(name: DataModel.constants.dataFailedToLoad, object: error))
} else {
let apps = $0
apps.forEach { app in
print("for each app - about to getNotificationSpecificationFromFireStore")
let queue = DispatchQueue(label: "getNotificationSpecificationFromFireStore_\(app.name)", qos: .utility, attributes: .concurrent)
queue.async { [weak self] in
print("getting Notification Specification from FireStore")
self?.getNotificationSpecificationFromFireStore(app: app) { [weak self] spec, error in
print("got Notification Specification from FireStore, about to post notification")
if(error != nil) {
return
}
guard let spec = spec else {
return
}
self?.postNotification(app: app, spec: spec)
}
}
}
// loadMergedForecasts($1)
NotificationCenter.default.post(Notification(name: DataModel.constants.predictionsDataLoaded))
}
callback()
}
}
}他们真的不需要像那样互相依赖,但是如果第一个失败了,做第二个没有意义。如果它们都成功了,我应该在postNotification中向收件人发送一个通知:
/** notify third party app of available notificatiions to schedule */
func postNotification (app: App, spec: NotificationSpecification) {
print("posting notification")
do {
let notify = Data(app.notify.utf8)
let localNotificationDetails = try JSONDecoder().decode(NotificationDetails.self, from: notify)
if spec.p8 != "custom" {
let token = localNotificationDetails.token
} else {
guard let bodyJSON = localNotificationDetails.body else {
return
}
guard let url = spec.custom_endpoint else { return }
guard let methodString = spec.custom_method?.uppercased() else { return }
guard let method = HTTPMethod(rawValue:methodString) else { return }
if ![.post, .put, .patch].contains(method) {
print("app has unsupported method '\(method)' -- \(String(describing: app))")
return
}
guard var headers = spec.custom_headers else { return }
if !headers.keys.map({ entry_key in entry_key.uppercased() }).contains("CONTENT-TYPE") {
headers["Content-Type"] = "application/json"
}
print("manually posting the notification with \(String(describing: bodyJSON))")
let queue = DispatchQueue(label: "manuallyPostNotifications", qos: .utility, attributes: .concurrent)
AF.request(url, method:method, parameters: bodyJSON).responseJSON(queue: queue) { response in
switch response.result {
case .success:
print("Validation Successful")
case .failure(let error):
print(error)
}
}
}
} catch let e {
print("error posting notification to app \(app.id)\n\(e)")
}
}这些方法都不在视图中。
一开始,没有任何提示,我不知道我是否通过了第一个loadPrediction。在当前状态下,当应用程序处于后台时,日志如下所示:
loading predictions
loading predictions - in async task, about to getPredictionsDataFromFirestore
getting Predictions Data from Firestore
for each app - about to getNotificationSpecificationFromFireStore
getting Notification Specification from FireStore编辑:这是额外的一行,但它并不代表额外队列的任何改进。
它将完成并成功,如果我前景(和他整个事情花了1-2秒,当充分在前景)。但我现在想做我所有的工作。
问题:
我排队不对。我怎么才能不排完我的队呢?
谁能确认或否认这将在应用程序关闭时工作吗?我可以看到,工作是在应用程序关闭时完成的,但之后我没有回去测试api调用是否工作,因为我不能让它在后台工作。
增编
修正后的当前答案代码
/** load prediction data for notification scheduling */
func loadPredictions(_ callback: @escaping () -> Void) {
print("loading predictions")
let queue = DispatchQueue(label: "loadingPredictions", qos: .default)
queue.sync { [weak self] in
let group = DispatchGroup()
group.enter()
print("loading predictions - in async task, about to getPredictionsDataFromFirestore")
self?.getPredictionsDataFromFirestore() { [weak self] in
print("getting Predictions Data from Firestore")
if let error = $2 {
NotificationCenter.default.post(Notification(name: DataModel.constants.dataFailedToLoad, object: error))
} else {
let apps = $0
apps.forEach { app in
print("for each app - about to getNotificationSpecificationFromFireStore")
group.enter()
print("getting Notification Specification from FireStore")
self?.getNotificationSpecificationFromFireStore(app: app) { [weak self] spec, error in
print("got Notification Specification from FireStore, about to post notification")
if(error != nil) {
group.leave()
return
}
guard let spec = spec else {
group.leave()
return
}
self?.postNotification(app: app, spec: spec) {
group.leave()
}
}
group.leave()
}
// loadMergedForecasts($1)
NotificationCenter.default.post(Notification(name: DataModel.constants.predictionsDataLoaded))
group.leave()
}
group.notify(queue: .main) {
callback()
print("I am being called too early?")
}
}
}
}和(在最后的方法调用中添加了一个回调):
/** notify third party app of available notificatiions to schedule */
func postNotification (app: App, spec: NotificationSpecification, _ callback: @escaping () -> Void ) {
print("posting notification")
do {
let notify = Data(app.notify.utf8)
let localNotificationDetails = try JSONDecoder().decode(NotificationDetails.self, from: notify)
if spec.p8 != "custom" {
let token = localNotificationDetails.token
callback()
} else {
guard let bodyJSON = localNotificationDetails.body else {
callback()
return
}
guard let url = spec.custom_endpoint else {
callback()
return
}
guard let methodString = spec.custom_method?.uppercased() else {
callback()
return
}
guard let method = HTTPMethod(rawValue:methodString) else {
callback()
return
}
if ![.post, .put, .patch].contains(method) {
print("app has unsupported method '\(method)' -- \(String(describing: app))")
callback()
return
}
guard var headers = spec.custom_headers else { return }
if !headers.keys.map({ entry_key in entry_key.uppercased() }).contains("CONTENT-TYPE") {
headers["Content-Type"] = "application/json"
}
print("manually posting the notification with \(String(describing: bodyJSON))")
let queue = DispatchQueue(label: "manuallyPostNotifications", qos: .utility, attributes: .concurrent)
AF.request(url, method:method, parameters: bodyJSON).responseJSON(queue: queue) { response in
switch response.result {
case .success:
print("Validation Successful")
case .failure(let error):
print(error)
}
callback()
}
}
} catch let e {
print("error posting notification to app \(app.id)\n\(e)")
callback()
}
}意识到我的打印声明不在通知回调中,我修改了它--仍然没有进入第二个firebase调用。
loading predictions
loading predictions - in async task, about to getPredictionsDataFromFirestore
getting Predictions Data from Firestore
for each app - about to getNotificationSpecificationFromFireStore
getting Notification Specification from FireStore
I am being called too early?发布于 2019-04-18 00:58:37
您正在触发异步任务,您的callback()将在这些任务完成之前执行。由于callback()最终调用了completionHandler,您的应用程序将在其所有工作完成之前被暂停。
您可以使用调度组来延迟callBack(),直到一切都完成。额外的调度队列是不必要的。
func loadPredictions(_ callback: @escaping () -> Void) {
print("loading predictions")
let dispatchGroup = DispatchGroup()
print("loading predictions - in async task, about to getPredictionsDataFromFirestore")
dispatchGroup.enter()
self.getPredictionsDataFromFirestore() {
print("getting Predictions Data from Firestore")
if let error = $2 {
NotificationCenter.default.post(Notification(name: DataModel.constants.dataFailedToLoad, object: error))
} else {
let apps = $0
apps.forEach { app in
print("for each app - about to getNotificationSpecificationFromFireStore")
dispatchGroup.enter()
self.getNotificationSpecificationFromFireStore(app: app) { spec, error in
print("got Notification Specification from FireStore, about to post notification")
if(error != nil) {
dispatchGroup.leave()
return
}
guard let spec = spec else {
dispatchGroup.leave()
return
}
self.postNotification(app: app, spec: spec)
dispatchGroup.leave()
}
}
}
NotificationCenter.default.post(Notification(name: DataModel.constants.predictionsDataLoaded))
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
callback()
}
}https://stackoverflow.com/questions/55736506
复制相似问题