2016-12-29 9 views
0

Я получаю до четырех push-уведомлений для каждого события, на которое я подписан. Я прошел через все, что связано с моими подписками CloudKit и реестром уведомлений, и я убежден, что это проблема Apple. Вместо этого я обратил внимание на правильную обработку уведомлений независимо от того, сколько я получаю. Вот упрощенная версия того, что я делаю:Создайте очередную очередь для сетевых вызовов, сгенерированных push-уведомлениями

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

Carl, Unsure, если я четко понял проблему, но здесь есть альтернативный подход к работе с несколькими [дублирующимися] уведомлениями. Это очень просто, просто используйте словарь для сохранения уведомлений по мере их поступления, чтобы вы могли легко распознать дубликаты. Таким образом, даже если вы получите второе или третье или более уведомление об одном и том же событии, это не имеет значения. Вы просто проверяете свой словарь и выбрасываете дубликат. – 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 
} 

} 

Просьба игнорировать разворот неаккуратных сил. Их нужно очистить.

 Смежные вопросы

  • Нет связанных вопросов^_^