Skip to content

Instantly share code, notes, and snippets.

@aqubi
Last active September 11, 2018 08:31
Show Gist options
  • Save aqubi/d45e350ab3d2dfa43469c487ee20053c to your computer and use it in GitHub Desktop.
Save aqubi/d45e350ab3d2dfa43469c487ee20053c to your computer and use it in GitHub Desktop.
let record = CKRecord(recordType: "MyType", recordID: recordID)
record["title"] = "name" as CKRecordValue?
record["price"]= 1 as CKRecordValue?
let subscription = CKDatabaseSubscription(subscriptionID: subscriptionID)
let notificationInfo = CKNotificationInfo()
notificationInfo.shouldSendContentAvailable = true
subscription.notificationInfo = notificationInfo
let operation = CKModifySubscriptionsOperation(subscriptionsToSave: [subscription], subscriptionIDsToDelete: nil)
operation.modifySubscriptionsCompletionBlock = { _, _, error in
print("added Database Subscriptions")
}
database.add(operation)
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
guard let userInfo = userInfo as? [String: NSObject] else { return }
let notification = CKNotification(fromRemoteNotificationDictionary: userInfo)
guard let subscriptionID = notification.subscriptionID else { return }
if notification.notificationType == .database {
//CKDatabaseSubscription
//subscriptionID から 該当のDatabaseを判断して、
//CKFetchDatabaseChangesOperation で変更情報を取得して反映する
} else if notification.notificationType == .recordZone {
guard let zoneNotification = notification as? CKRecordZoneNotification else { return }
guard let recordZoneID = zoneNotification.recordZoneID else { return }
//CKRecordZoneSubscription
//recordZoneIDから該当のRecord Zoneを判断して、
//CKFetchRecordZoneChangesOptions で変更情報を取得して反映する
} else if notification.notificationType == .query {
guard let queryNotification = notification as? CKQueryNotification else { return }
guard let recordID = queryNotification.recordID else { return }
let recordZoneID = recordID.zoneID
//CKQuerySubscription
//対象のRecordIDがNotificationから取得できる
}
}
let operation = CKFetchDatabaseChangesOperation(previousServerChangeToken: cachedToken)
operation.fetchDatabaseChangesCompletionBlock = { serverChangeToken, moreComing, error in
if let e = error {
if let ckError = e as? CKError, ckError.code == .changeTokenExpired {
print("token expired")
}
return
}
print("new token is ", serverChangeToken)
}
var currentToken:String?
func fetchChanges(from database: CKDatabase) {
 let operation = CKFetchDatabaseChangesOperation(previousServerChangeToken: currentToken)
var newZoneIDs = [CKRecordZoneID]()
operation.changeTokenUpdatedBlock = { serverChangeToken in
//Databaseの新しいTokenを保存しておき、次回に利用する
self.currentToken = serverChangeToken
}
operation.recordZoneWithIDWasDeletedBlock = { zoneID in
//対象のRecord Zoneをキャッシュから削除する
}
operation.recordZoneWithIDChangedBlock = { zoneID in
if {キャッシュに対象のRecordZoneがあれば} {
//Record Zoneの差分を取得して更新する
} else {
newZoneIDs.append(zoneID)
}
}
operation.fetchDatabaseChangesCompletionBlock = { serverChangeToken, moreComing, error in
if CloudKitError.share.handle(error: error, operation: .fetchChanges, alert: true) != nil {
if let ckError = error as? CKError, ckError.code == .changeTokenExpired {
//トークン切れ
self.currentToken = nil
self.fetchChanges(from: database)
}
return
}
self.currentToken = serverChangeToken
guard moreComing == false else { return }
guard newZoneIDs.count > 0 else { return }
//新しいRecord Zoneの処理
let fetchZonesOp = CKFetchRecordZonesOperation(recordZoneIDs: newZoneIDs)
fetchZonesOp.fetchRecordZonesCompletionBlock = { results, error in
guard error == nil, let zoneDictionary = results else { return }
for (_, zone) in zoneDictionary {
//Record Zoneをキャッシュに追加して、内容を取得する
}
}
database.add(fetchZonesOp)
}
database.add(operation)
}
let options = CKFetchRecordZoneChangesOptions()
options.previousServerChangeToken = cachedToken
let zone:CKRecordZone = ...
let operation = CKFetchRecordZoneChangesOperation(recordZoneIDs: [zone.zoneID], optionsByRecordZoneID: [zone.zoneID: options])
operation.recordZoneFetchCompletionBlock = { (zoneID, serverChangeToken, clientChangeTokenData, moreComing, error) in
if let e = error {
if let ckError = e as? CKError, ckError.code == .changeTokenExpired {
print("token expired")
}
return
}
print("new token is ", serverChangeToken)
}
let operation = CKModifyRecordsOperation(recordsToSave: recordsToSave, recordIDsToDelete: nil)
operation.longLivedOperationWasPersistedBlock = {
print("Call longLivedOperationWasPersistedBlock ID=", operation.operationID)
UserDefaults.standard.setValue(operation.operationID, forKey: "LongLivedOperationID")
UserDefaults.standard.synchronize()
}
let configuration = CKOperationConfiguration()
configuration.isLongLived = true
operation.configuration = configuration
database.add(operation)
let container = CKContainer.default()
//全てのIDを取得
container.fetchAllLongLivedOperationIDs { (operationIDs, error) in
print("called fetchAllLongLivedOperationIDs")
if let e = error { print(e) }
if let ids = operationIDs {
print("operationIDs count=", ids.count)
}
}
//保存したOperationIDから検索
if let longLivedID = UserDefaults.standard.string(forKey: "LongLivedOperationID") {
container.fetchLongLivedOperation(withID: longLivedID, completionHandler: { (operation, error) in
if let e = error {
print(e)
} else if let ope = operation {
print("find operation ID=", ope.operationID)
}
})
}
let database = CKContainer.default().privateCloudDatabase
let operation = CKModifyRecordsOperation(recordsToSave: recordsToSave, recordIDsToDelete: recordIDsToDelete)
operation.modifyRecordsCompletionBlock = { (records, recordIDs, error) in
//TODO:
}
operation.database = database
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options:[.alert]) { (granted, error) in
  assert(granted == true)
}
UIApplication.shared.registerForRemoteNotifications()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment