我正在使用Swift/Xcode构建一个原生iOS应用程序,它利用来自第三方应用程序接口的JOSN数据。一切都很正常,但是API对每小时可以调用API的次数有限制。因此,现在我正在构建一个函数,用于在CloudKit中创建一个每周一次的数据库作为CK Asset,它将每6小时从API更新一次JSON。这样,数据仍然是相对最新的,但也将API调用的数量减少到每天4次。
注意:该应用程序正在Production/TestFlight中测试。
在CloudKit中创建要另存为新CKRecord的新CKAsset时,函数工作正常。该功能还可以正确地从CloudKit下载和解码CKAsset,以便在应用程序中使用。<-任何人都可以下载这个资源,并且它工作得很好。
问题:每当该函数检查CKAsset是否超过6小时时,它都应该允许任何用户通过下载较新的JSON文件并使用CKModifyRecordsOperation在CKRecord的CKAsset中替换它来修改CKRecord。问题是,每当另一个用户试图修改记录时,应用程序就会崩溃。
问:为什么其他使用TestFlight的用户不能修改记录?我使用CKModifyRecordsOperation是不是错了?
如有任何帮助或建议,我们不胜感激!
--CODE/FUNC
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}
发布于 2021-08-12 17:28:04
因此,这个答案的解决方案分为三个部分,因为我基本上遇到了三个问题。
一-当我第一次创建我的函数时,我使用CK数据类型"Bytes“和"String”来保存我的JSON,但我得到了一个错误,因为我的JSON的大小超过了这些数据类型所符合的1mb限制。我没有意识到大小限制导致了错误,相反,我认为是保存功能不起作用,所以我切换到使用CKModifyRecord来尝试保存。一旦失败,我就注意到了大小限制,转而使用CKAsset来保存数据库。这修复了限制,但在保存或修改CK记录的资产时,我仍然收到错误。
第二,由于大小不再是问题,我做了一些挖掘,发现CloudKit中的安全权限拒绝其他用户保存不是他们创建的记录。为了解决这个问题,我进入CK Dashboard,在“模式”部分找到了“安全角色”。我将角色从“创建者”切换为" iCloud“,以允许所有连接的iCloud用户编辑记录。
三--我遇到的最后一个问题是找出我从TestFlight测试人员那里得到的错误。在此之前,我从未尝试过访问TestFlight用户的崩溃日志,我认为这是一个漫长而复杂的过程。不-- Xcode内置了开箱即用的功能,不需要配置。(1)在Xcode打开的情况下,单击顶部菜单中的窗口>管理器,打开管理器窗口。

(2)从这里你可以看到你存档并提交给试飞的每个构建的所有崩溃日志。而且,您甚至可以在Xcode中运行它们,通过单击“在Xcode中打开”按钮来查找导致程序崩溃的行/错误。

https://stackoverflow.com/questions/68733952
复制相似问题