2016-12-29 42 views
0

對於我訂閱的每個事件,我最多接收四個推送通知。我經歷了與我的CloudKit訂閱和通知註冊表相關的所有事情,我確信這是一個Apple問題。無論我收到多少通知,我都會將注意力轉向正確處理通知。下面是我在做什麼的簡化版本:爲推送通知生成的網絡呼叫創建串行隊列

func recievePrivatePush(_ pushInfo: [String:NSObject], completion: @escaping()->Void) { 

    let notification = CKNotification(fromRemoteNotificationDictionary: pushInfo) 
    let alertBody = notification.alertBody 

    if let queryNotification = notification as? CKQueryNotification { 
     let recordID = queryNotification.recordID 
     guard let body = queryNotification.alertBody else { 
      return 
     } 

     if recordID != nil { 
      switch body { 
      case "Notification Type": 
       let id = queryNotification.recordID 
       switch queryNotification.queryNotificationReason { 
       case .recordCreated: 
        DataCoordinatorInterface.sharedInstance.fetchDataItem(id!.recordName, completion: { 
         // 
        }) 
        break 

       default: 
        break 
       } 
      } 
     } 
    } 
} 

的抓取代碼看起來是這樣的:

func fetchDataItem(_ id: String, completion: @escaping()-> Void) { 

    if entityExistsInCoreData(id) {return} 


    let db = CKContainer.default().privateCloudDatabase 
    let recordID = CKRecordID(recordName: id) 
    db.fetch(withRecordID: recordID) { (record, error) in 
     if let topic = record { 
      //Here I create and save the object to core data. 
     } 
     completion() 
    } 
} 

我所有的代碼工作,我遇到的問題是,當我收到多個通知,在創建第一個核心數據實體之前啓動多個提取請求,從而產生冗餘的核心數據對象。

我想要做的是找到一種方法來將提取請求添加到串行隊列,以便它們一次處理一個。我可以將我的請求調用放入一個串行隊列中,但回調總是異步運行,因此在第一個數據對象被保存之前,仍然會發出多個提取請求。

我已經使用信號量和調度組,看起來像這樣的圖案的嘗試:

let semaphore = DispatchSemaphore(value: 1)  

func recievePrivatePush(_ pushInfo: [String:NSObject], completion: @escaping()->Void) { 

    _ = semaphore.wait(timeout: .distantFuture) 

    let notification = CKNotification(fromRemoteNotificationDictionary: pushInfo) 
    let alertBody = notification.alertBody 

    if let queryNotification = notification as? CKQueryNotification { 
     let recordID = queryNotification.recordID 
     guard let body = queryNotification.alertBody else { 
      return 
     } 

     if recordID != nil { 
      switch body { 
      case "Notification Type": 
       let id = queryNotification.recordID 
       switch queryNotification.queryNotificationReason { 
       case .recordCreated: 
        DataCoordinatorInterface.sharedInstance.fetchDataItem(id!.recordName, completion: { 
         semaphore.signal() 
        }) 
        break 

       default: 
        break 
       } 
      } 
     } 
    } 
} 

一旦上述函數被調用用於所述第二時間,並且semaphore.wait被調用時,所述第一執行網絡請求暫停,導致一個凍結的應用程序。

再次,我想完成它將異步網絡請求添加到一個隊列,使它們一次只有一個,即第一個網絡調用是在第二個請求開始之前完成的。

+1

卡爾,不確定我是否清楚地理解了這個問題,但這裏是一個處理多個[重複]通知的替代方法。它非常直接,只需使用字典即可​​保存通知,以便您可以輕鬆識別重複項。這樣,即使你得到第二次或第三次或更多的同一事件的通知,這也沒有關係。你只是檢查你的字典,扔掉重複。 – user3069232

+0

問題仍然是通知幾乎同時到達,並由應用程序委託並行處理。在有時間向字典添加鍵值對並檢查它之前,我會得到一些誤報。 – CarlNathan

回答

0

卡爾,

也許你還會與調度組找到您的解決方案,一些關鍵的表達式來看看。

let group = DispatchGroup() 
group.enter() 

... ...代碼

group.leave 
group.wait() 

我用它們來限制HTTP請求我在批量發送,數量等待響應。也許你可以將它們與我評論中的建議一起使用。觀看這個視頻,在這裏派遣小組,我想更多。

https://developer.apple.com/videos/play/wwdc2016/720/ 
+0

感謝您的回答。我發現調度組和信號量不適合這個特殊的問題。我從你之前的評論中得到了一些建議。我最終做了什麼來創建一個串行隊列來管理對一個數組的訪問,而不是實際發出請求,結果我工作的很好。謝謝您的幫助!我會用工作代碼更新我的問題。 – CarlNathan

0

這些簡單的課程幫助我解決了這個問題。

class PushQueue { 

internal var pushArray: Array<String> = [String]() 
internal let pushQueue = DispatchQueue(label: "com.example.pushNotifications") 

public func addPush(_ push: Push) { 
    pushQueue.sync { 
     if pushArray.contains(push.id) { 
      return 
     } else { 
      pushArray.append(push.id) 
      processNotification(push: push) 
     } 
    } 
} 

internal func processNotification(push: Push) { 
    PushInterface.sharedInstance.recievePrivatePush(push.userInfo as! [String: NSObject]) 
} 

} 


class CKPush: Equatable { 

init(userInfo: [AnyHashable: Any]) { 

    let ck = userInfo["ck"] as? NSDictionary 
    let id = ck?["nid"] as? String 
    self.id = id! 
    self.userInfo = userInfo 
} 

var id: String 
var userInfo: [AnyHashable:Any] 

public static func ==(lhs: CKPush, rhs: CKPush) -> Bool { 
    return lhs.id == rhs.id ? true : false 
} 

} 

請忽略鬆散的力量展開。他們需要清理。