Я пытаюсь создать очень простой интерфейс между CloudKit и моим локальным хранилищем данных.В своей функции я выбираю текущие данные и сравниваю их с локальными данными.Новые автономные записи попадают в один массив, а автономные удаления - в другой массив.Они сохраняются в CloudKit с помощью CKModifyRecordsOperation.Затем в обработчике завершения я вызываю операцию выполнения для получения обновленных данных.
К сожалению, я не получаю новые записи в этой выборке.Удаление не включено, но я просто не получаю новые записи из CloudKit.Вот голые кости моих функций.
static func sync(
completion: @escaping (
_ results: [Pet],
_ error: NSError?) -> ())
{
var petsToDelete = [CKRecordID]()
var petsToSave = [CKRecord]()
//Empty any existing pet array
pets = []
//load local pets into an array
if let localPets = loadPetsLocal() {
//Set up the array for CloudKit Pets
fetchFromCloud(){ (results , error) -> () in
cloudPets = results
//Use records marked for deletion to mark the CKRecords for deletion and put them into an array for saving to CloudKit
for localPet in localPets {
//MARK: RECON DELETIONS (Offline deletions of CKRecords)
//Check to see if the record is marked for deletion (marked while off the CloudKit) and put them in an array
if localPet.petName.lowercased().range(of: "delete me") != nil{
//If the record is marked for deletion, iterate through the pets array to find the related CKRecord
for petToDelete in cloudPets{
if localPet.recordName == petToDelete.recordID.recordName{
//Put this record into the deletion array of CKRecordIDs
petsToDelete.append(petToDelete.recordID)
}
}
}
//Put all new records (recordName = "Local") into an array for saving to CloudKit
if localPet.recordName == "Local" {
changedRecord = CKRecord(recordType: RemoteRecords.pet, zoneID: ArendK9DB.share.zoneID)
changedRecord?[RemotePet.petName] = localPet.petName as NSString
changedRecord?[RemotePet.dob] = localPet.dob as NSDate?
changedRecord?[RemotePet.petSex] = localPet.petSex as NSString?
//Some special handling to get the UIImage into a CKAsset
if let photo = localPet.photo {
let imageData:Data = UIImageJPEGRepresentation(photo, 1.0)!
let path:String = Pet.documentsDirectoryPath.appendingPathComponent(Pet.tempImageName)
try? UIImageJPEGRepresentation(photo, 1.0)!.write(to: URL(fileURLWithPath: path), options: [.atomic])
Pet.imageURL = URL(fileURLWithPath: path)
try? imageData.write(to: Pet.imageURL, options: [.atomic])
let File:CKAsset? = CKAsset(fileURL: URL(fileURLWithPath: path))
changedRecord?[RemotePet.photo] = File as! CKAsset
}
petsToSave.append(changedRecord!)
}
}
//There is a lot more code here to check for records that have changed
**strong text**//If nothing changed, just return the original array
if petsToDelete == [] && petsToSave == [] {
print("DEBUG I have nothing to save")
if error != nil {
print(error?.localizedDescription ?? "General Query Error: No Description")
} else {
/*guard let records = results else {
return
}*/
for record in results {
if let pet = Pet(remoteRecord: record) {
self.pets.append(pet)
}
}
completion(pets, nil)
}
} else {
//Save the new and deleted records to CloudKit
saveUpdateCloud(petsToSave: petsToSave, recordIDsToDeleve: petsToDelete)
{ (results , error) -> () in
if error != nil {
print(error?.localizedDescription ?? "General Query Error: No Description")
} else {
print("DEBUG: I have returned to the Recon from the update and isFinished is \(results) and pets is \(pets)")
//Grab the new, updated list of CKRecords
fetchFromCloud(){ (r , e) -> () in
print("DEBUG Loading new CloudKit array at \(Date())")
if e != nil {
print(e?.localizedDescription ?? "General Query Error: No Description")
} else {
for record in r {
if let pet = Pet(remoteRecord: record) {
pets.append(pet)
}
}
//Save this new array locally
print("DEGUG Saving records to local store")
pets[0].saveToLocal(petsToSave: self.pets)
print("DEBUG I have a new pet array from CloudKit \(pets)")
completion(pets, nil)
}
}
}
}
}
}
} else {
fetchFromCloud(){ (r , e) -> () in
print("DEBUG There is no local data so I am returning a new CloudKit array \(r)")
if e != nil {
print(e?.localizedDescription ?? "General Query Error: No Description")
} else {
for record in r {
if let pet = Pet(remoteRecord: record) {
pets.append(pet)
}
}
//Save this new array locally
print("DEGUG Saving records to local store")
pets[0].saveToLocal(petsToSave: self.pets)
print("DEBUG I have a new pet array from CloudKit \(pets)")
completion(pets, nil)
}
}
}
}
//MARK: Fetch current records from CloudKit
static func fetchFromCloud(
completion: @escaping (
_ results: [CKRecord],
_ error: NSError?) -> ())
{
print("Fetch from CloudKit... starting completion handler")
//Retrieve CloudKit data into an arry for reference
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: RemoteRecords.pet, predicate: predicate)
ArendK9DB.share.privateDB.perform(query, inZoneWith: ArendK9DB.share.zoneID, completionHandler: {(records: [CKRecord]?, e: Error?) in
if e != nil {
print(e?.localizedDescription ?? "General Query Error: No Description")
} else {
guard let records = records else {
return
}
print("DEBUG Fetching from CloudKit... ending completion handler with records = \(records)")
completion(records, nil)
}
}
)
}
//MARK: Save new records and delete records for multiple Pets
static func saveUpdateCloud(petsToSave: [CKRecord]?, recordIDsToDeleve: [CKRecordID]?,
completion: @escaping (
_ results: Bool,
_ error: NSError?) -> ())
{
//Execute the operation
var savedRecordNames = [String]()
let saveOperation = CKModifyRecordsOperation(recordsToSave: petsToSave, recordIDsToDelete: recordIDsToDeleve)
saveOperation.perRecordCompletionBlock = {
record, error in
if error != nil {
print(error!.localizedDescription)
} else {
print("Saving Record to Cloud: \(record)")
savedRecordNames.append(record.recordID.recordName)
}
}
saveOperation.completionBlock = {
print("DEBUG In the completion block therefore isFinished is \(saveOperation.isFinished) at \(Date())")
completion(saveOperation.isFinished, nil)
}
ArendK9DB.share.privateDB.add(saveOperation)
}