我正在使用 Swift/Xcode 构建一个本机 iOS 应用程序,该应用程序利用来自 3rd 方 API 的 JOSN 数据。一切正常,但 API 限制了您每小时可以调用 API 的次数。所以现在我正在构建一个函数,旨在创建一个每周数据库作为 CloudKit 中的 CK 资产,它将每 6 小时从 API 更新 JSON。这样,数据仍然是相对最新的,但也将 API 调用次数减少到每天仅 4 次。
注意:该应用程序正在 Production/TestFlight 中进行测试。
该函数在创建新的 CKAsset 以在 CloudKit 中另存为新的 CKRecord 时正常工作。该函数还正确地从 CloudKit 下载和解码 CKAsset 以在应用程序中使用。<- 任何人都可以下载此资产,并且运行良好。
问题:每当函数检查 CKAsset 是否超过 6 小时时,它应该让任何用户通过下载更新的 JSON 文件并使用 CKModifyRecordsOperation 将其替换到 CKRecord 的 CKAsset 中来修改 CKRecord。问题是,每当另一个用户尝试修改记录时,应用程序就会崩溃。
问题:为什么其他使用TestFlight的用户不能修改记录?使用 CKModifyRecordsOperation 我错了吗?
非常感谢任何帮助或建议!
-------------------------------------------代码/功能---- ----------------
func fetchWeeklyPlayersDB() {
let semaphore = DispatchSemaphore.init(value: 0)
let thisWeek = getCurrentWeekID()
let current = Date()
// fetch current week PlayersDB from CK Database
publicDB.fetch(withRecordID: CKRecord.ID(recordName:thisWeek + "_Players")) { record, error in
// process record
if let r = record { // we know the playersDB has data
let modified = r.modificationDate
let expirationDate = modified?.addingTimeInterval(6*60*60) // add 6 hours
// if CK DB expirationDate is less than now, use it
if expirationDate! > current {
// not outdated - just process
if let data = r["DB"] {
// decode the JSON and set it to rawData
let d = readCKAsset(asset: data as! CKAsset)
let result = try? JSONDecoder().decode(dfsAPIData.self, from: d as! Data)
rawData = result
semaphore.signal()
}
} else { // CK DB is more than 6 hours old, call api and overwite data
// call API
let apiData = callAPI(week: findWeek())
// encode the api data as NSData
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(apiData)
// save data locally
if let path = saveJSON(data: jsonData) {
// convert result to CKASset using local save filepath
let asset:CKAsset = CKAsset.init(fileURL: path)
r["DB"] = asset
// Modify PlayersDB value in CKRecord
let modifyRecord = CKModifyRecordsOperation(recordsToSave: [r], recordIDsToDelete: nil)
modifyRecord.savePolicy = CKModifyRecordsOperation.RecordSavePolicy.allKeys
modifyRecord.qualityOfService = QualityOfService.userInitiated
modifyRecord.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
if error == nil {
// we did it!
print("PlayersDB Successfully overwritted with update api data")
// delete the file you created
deleteJSON(path: path)
rawData = apiData
semaphore.signal()
} else {
print("ERROR SAVING PlayersDB TO CK" + error!.localizedDescription)
// delete the file you created
deleteJSON(path: path)
// pull from the CK DB anyway so it fails softly
if let data = r["DB"] {
// decode the JSON and set it to rawData
let d = readCKAsset(asset: data as! CKAsset)
let result = try? JSONDecoder().decode(dfsAPIData.self, from: d as! Data)
rawData = result
semaphore.signal()
}
}
}
publicDB.add(modifyRecord)
}
}
catch {
print("Error Encoding JSON - WTF")
// if encoding fails - pull latest db instead to fail softly
if let data = r["DB"] {
// decode the JSON and set it to rawData
let d = readCKAsset(asset: data as! CKAsset)
let result = try? JSONDecoder().decode(dfsAPIData.self, from: d as! Data)
rawData = result
semaphore.signal()
}
}
}
}
// process error - DB doesnt exist, Call API and Create It
if let e = error {
// call API
let apiData = callAPI(week: findWeek())
// create record
let recordID = CKRecord.ID(recordName:thisWeek + "_Players")
let record = CKRecord(recordType: "WeeklyDB", recordID: recordID)
// encode the api data as NSData
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(apiData)
if let path = saveJSON(data: jsonData) {
// convert result to CKASset using local save filepath
let asset:CKAsset = CKAsset.init(fileURL: path)
record["DB"] = asset
// Save DB to CK
publicDB.save(record, completionHandler: {returnRecord, error in
if let err = error {
// something happened
print("ERROR SAVING PlayersDB TO CK" + err.localizedDescription)
} else {
// we did it!
print("PlayersDB Successfully overwritted with update api data")
// delete the file you just created
deleteJSON(path: path)
rawData = apiData
semaphore.signal()
}
})
}
}
catch {
print("Error Encoding JSON while saving api data to PlayersDB - WTF")
}
}
}
semaphore.wait()
return
}