我正在尝试使用CloudKit保持多个设备同步。具体来说,我试图根据iCloud / CloudKit中存储的内容保持动作数据(动作人物细节)的属性一致。我正在使用订阅来在记录发生变化时通知。更新记录触发并收到很好。如果我将订阅分成两个单独的订阅 - 1个用于创建,1个用于更新,则不会触发。
let actionFigureRefernece = CKReference(recordID: actionFigureRecordId, action: .deleteSelf)
let predicate = NSPredicate(format:"actionFigureReference == %@", actionFigureRefernece)
图引用和细节属性的表布局:
actionFigureReference Reference
haveFigureCount Int(64)
haveTheFigure Int(64)
这是代码。
func saveActionFigureSpecifics() {
// set and save core data
actionFigureSpecificsCoreData!.updateDate = NSDate()
SharedData.sharedInstance.appDelegate.saveContext()
// save to iCloud based on user preference
if SharedData.sharedInstance.isUserPreferenceToUseICloud == true {
// Private Database
let privateDatabase = SharedData.sharedInstance.privateDatabase
// record IDs
let actionFigureRecordId = CKRecordID(recordName: actionFigureGlobalUniqueId)
let actionFigureSpecificRecordId = CKRecordID(recordName: actionFigureSpecificsGlobalUniqueId)
// Initialize Reference
if actionFigureSpecificsRecord == nil {
// set the record type
actionFigureSpecificsRecord = CKRecord(recordType: kActionFigureSpecificsRecord, recordID: actionFigureSpecificRecordId)
// set the record details
let actionFigureReference = CKReference(recordID: actionFigureRecordId, action: .deleteSelf)
actionFigureSpecificsRecord!.setObject(actionFigureReference, forKey: kActionFigureReference)
}
// iCloud attributes
actionFigureSpecificsRecord!.setObject(actionFigureSpecificsCoreData!.haveTheFigure as CKRecordValue?, forKey: kHaveTheFigure)
actionFigureSpecificsRecord!.setObject(actionFigureSpecificsCoreData!.haveFigureCount as CKRecordValue?, forKey: kHaveFigureCount)
actionFigureSpecificsRecord!.setObject(actionFigureSpecificsCoreData!.wantTheFigure as CKRecordValue?, forKey: kWantTheFigure)
actionFigureSpecificsRecord!.setObject(actionFigureSpecificsCoreData!.updateDate as CKRecordValue?, forKey: kUpdateDate)
// Create subscription
// push notification
self.saveActionFigureSpecificsICloudSubscriptions(withReference: actionFigureRecordId) {
results, error in
if let error = error {
print("Error saving subscription: \(error.localizedDescription)")
}
// Save Record
privateDatabase!.save(self.actionFigureSpecificsRecord!) { (actionFigureRecord, error) -> Void in
if (error != nil) {
DispatchQueue.main.async {
#if DEBUG
print("WARNING: Error saving specifics of \(actionFigureRecordId.recordName) \(error!)")
#endif
self.isActionFigureSpecificSetFromICloud = false
}
} else {
DispatchQueue.main.async {
// set the record to the saved record.
self.actionFigureSpecificsRecord = actionFigureRecord!
let actionFigureReference = actionFigureRecord!.object(forKey: kActionFigureReference) as! CKReference
let actionFigureRecoreId = actionFigureReference.recordID
#if DEBUG
print("Save executed and successful on \(kActionFigureSpecificsRecord) for \(actionFigureRecoreId.recordName)")
#endif
}
}
}
}
}
}
订阅增加
func saveActionFigureSpecificsICloudSubscriptions(withReference actionFigureRecordId: CKRecordID, completion : @escaping (_ results: CKSubscription?, _ error : Error?) -> Void) {
let privateDatabase = SharedData.sharedInstance.privateDatabase
let subscriptionId = "\(actionFigureRecordId.recordName)_\(kActionFigureSpecificsRecord)_Subscription"
// get subscriptions
privateDatabase?.fetchAllSubscriptions(completionHandler: { (subscriptions, error) in
if let err = error {
#if DEBUG
print("Fetch subscription failed \(err.localizedDescription)")
#endif
completion(nil, err)
return
} else {
var isSubscriptionCreated: Bool = false
for subscription in subscriptions! {
//if subscriptionId == subscription.subscriptionID {
if subscription.subscriptionID.contains(subscriptionId) {
#if DEBUG
print("subscription detail exists for \(subscription.subscriptionID)")
#endif
isSubscriptionCreated = true
}
}
// if the subscription doesn't exist, create the subscription
if isSubscriptionCreated == false {
let actionFigureRefernece = CKReference(recordID: actionFigureRecordId, action: .deleteSelf)
let predicate = NSPredicate(format:"actionFigureReference = %@", actionFigureRefernece)
//let predicate = NSPredicate(value: true)
let subscriptionIdInsert = "\(subscriptionId)"
let subscription = CKQuerySubscription(recordType: kActionFigureSpecificsRecord, predicate: predicate, subscriptionID: subscriptionIdInsert, options: [.firesOnRecordCreation, .firesOnRecordUpdate])
let notification = CKNotificationInfo()
var actionFigure: ActionFigure?
if let specificsDelegate = self.delegate as? ActionFigure {
actionFigure = specificsDelegate
notification.alertBody = "Action figure specifics \(actionFigure!.series) \(actionFigure!.actionFigureName) updated"
}
else {
notification.alertBody = "Action figure specifics updated"
}
notification.shouldBadge = true
notification.soundName = "default"
subscription.notificationInfo = notification
privateDatabase?.save(subscription, completionHandler: ({returnRecord, error in
if let err = error {
#if DEBUG
print("subscription creation failed \(err.localizedDescription)")
#endif
completion(nil, err)
return
} else {
DispatchQueue.main.async() {
#if DEBUG
print("Success: Subscription set up successfully for specifics on \(subscriptionId)")
#endif
completion(returnRecord, nil)
return
}
}
}))
}
else { // subscription exists
completion(nil, nil)
return
}
}
})
}
AppDelegate功能
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
SharedDataToyLine.sharedInstance.setToyLines()
// Register to receive notification
//create the notificationCenter
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options: [.alert]) { (granted, error) in
// nothing to do yet
}
application.registerForRemoteNotifications()
// Google adds
FIRApp.configure()
GADMobileAds.configure(withApplicationID: kGADMobileAdsMobileAppId)
// Amazon adds
AmazonAdRegistration.shared().setAppKey(kAmazonMyToyChestAPIKey)
return true
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (_ options: UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
let notification: CKNotification = CKNotification(fromRemoteNotificationDictionary: notification.request.content.userInfo as! [String : NSObject])
if (notification.notificationType == CKNotificationType.query) {
let queryNotification = notification as! CKQueryNotification
let recordId: CKRecordID = queryNotification.recordID!
#if DEBUG
print("Foreground push for record name returned from push \(recordId.recordName)")
#endif
if let shareDataActionFigureArrayIndex = SharedDataActionFigure.sharedInstance.getIndexForActionFigure(byActionFigureSpecificsRecordId: recordId) {
#if DEBUG
print("Record index for push \(recordId.recordName) is \(shareDataActionFigureArrayIndex)")
#endif
SharedDataActionFigure.sharedInstance.actionFigureArray[shareDataActionFigureArrayIndex].actionFigureSpecifics.setActionFigureSpecificsFromPushNotification()
}
}
}
订阅
RecordType
ActionFigureSpecifics
Trigger
UPDATE<br>INSERT
Criteria
ActionFigureSpecifics.actionFigureReference (equals reference)