当前位置: 动力学知识库 > 问答 > 编程问答 >

ios - CloudKit subscriptions not saving on iOS10

问题描述:

I'm following the 'CloudKit Best Practices' WWDC talk about adding subscriptions, which seems to have changed in iOS10.

The code below returns a 'Success!', however my 'AllChanges' subscription never appears in Subscription Types on CloudKit Dashboard.

I'm on Xcode 8 beta 6.

 let subscription = CKDatabaseSubscription(subscriptionID:"AllChanges")

let notificationInfo = CKNotificationInfo()

notificationInfo.shouldSendContentAvailable = true

subscription.notificationInfo = notificationInfo

let operation = CKModifySubscriptionsOperation(subscriptionsToSave: [subscription], subscriptionIDsToDelete: [])

operation.modifySubscriptionsCompletionBlock = {

(modifiedSubscriptions: [CKSubscription]?, deletedSubscriptionIDs: [String]?, error: Error?) -> Void in

if error != nil {

print(error!.localizedDescription)

} else {

print("Success!")

}

}

operation.qualityOfService = .utility

privateDatabase.add(operation)

网友答案:

I have had the same problem with CKDatabaseSubscription, as have many others:

  • https://forums.developer.apple.com/thread/53546
  • https://forums.developer.apple.com/thread/61267
  • https://forums.developer.apple.com/thread/64071
  • https://forums.developer.apple.com/thread/63917

I am listing some caveats first in case they explain your issue:

  • subscriptions often do not appear in "Developer" CloudKit dashboard (they exist, but are not shown - easiest way to test is rename subscription and see if CloudKit complains about duplicate subscriptions)
  • push notifications are not sent to Simulator

Solution:

What fixed this for me was to create a custom private zone and save all my data to that zone (works in private databases only). Then I receive push notifications on any changes to that zone.

You will need to create the zone (-after- checking for CKAccountStatus = .available and -before- any record saves):

let operation = CKModifyRecordZonesOperation(recordZonesToSave: [CKRecordZone(zoneName: "MyCustomZone")], recordZoneIDsToDelete: nil)
operation.modifyRecordZonesCompletionBlock = { (savedRecordZones: [CKRecordZone]?, deletedRecordZoneIDs: [CKRecordZoneID]?, error: Error?) in
    if let error = error {
        print("Error creating record zone \(error.localizedDescription)")
    }
}
privateDatabase?.add(operation)

And then use that zone when saving your records:

let record = CKRecord(recordType: "MyRecordType", zoneID: CKRecordZone(zoneName: "MyCustomZone")) 
// you can save zone to CKRecordID instead, if you want a custom id

Then skip CKFetchDatabaseChangesOperation (because we already know our zone), and use CKFetchRecordZoneChangesOptions instead:

let options = CKFetchRecordZoneChangesOptions()
options.previousServerChangeToken = myCachedChangeToken
let operation = CKFetchRecordZoneChangesOperation(
    recordZoneIDs: [myCustomZoneId],
    optionsByRecordZoneID: [myCustomZoneId: options]
)
operation.fetchAllChanges = true
operation.recordChangedBlock = { (record: CKRecord) -> Void in
        ... do something
}
operation.recordWithIDWasDeletedBlock = { (recordId: CKRecordID, recordType: String) -> Void in
        ... do something
}
operation.recordZoneFetchCompletionBlock = { (recordZoneId, changeToken, tokenData, isMoreComing, error) in
    if let error = error {
        print("Error recordZoneFetchCompletionBlock: \(error.localizedDescription)")
        return
    }
    myCachedChangeToken = changeToken
}
privateDatabase?.add(operation)
分享给朋友:
您可能感兴趣的文章:
随机阅读: