- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我的应用程序中有 2 个 View Controller 。
第一个“MainViewController”显示一个 tableView,其中包含从私有(private) CloudKit 数据库获取的 CKRecords 字段。在此 VC 的 viewWillAppear 方法中,我从 CloudKit 获取记录并重新加载 TableView 的数据以显示用户先前保存在 CloudKit 中的最新获取结果。
第二个 View Controller “CreateRecordViewController”用于创建 CKRecords 并将它们保存到 CloudKit 的私有(private)数据库中。
所以我在 CreateRecordViewController 中创建记录并在 MainViewController 中显示它们。
问题如下:当我在 CreateRecordViewController 中创建记录时,它保存在 CloudKit 服务器上,但是在关闭此 CreateRecordViewController 并转到 MainViewController 之后,tableview 并不总是及时更新。
这是在我的 CreateRecordViewController 中保存记录的代码:
CloudKitManager.sharedInstance.privateDatabase.save(myRecord) { (savedRecord, error) -> Void in
if error == nil {
print("successfully saved record code: \(savedRecord)")
}
else {
// Insert error handling
print("error Saving Data to iCloud: \(error.debugDescription)")
}
}
保存记录后,我关闭 CreateRecordViewController 并查看 MainViewController。
正如我之前在 MainViewController 的 viewWillAppear 中所说,我检查 iCloud 是否可用,如果可用,我通过 CloudKit 的查询获取所有记录并将它们显示在 tableView 中。
override func viewWillAppear(_ animated: Bool) {
CKContainer.default().accountStatus { (accountStatus, error) in
switch accountStatus {
case .noAccount: print("CloudKitManager: no iCloud Alert")
case .available:
print("CloudKitManager: checkAccountStatus : iCloud Available")
self.loadRecordsFromiCloud()
case .restricted:
print("CloudKitManager: checkAccountStatus : iCloud restricted")
case .couldNotDetermine:
print("CloudKitManager: checkAccountStatus : Unable to determine iCloud status")
}
}
}
在 loadRecordsFromiCloud() 中,我还会在查询成功时异步重新加载 tableview 以显示最新结果。
我的 MainViewController 中的 loadRecordsFromiCloud 方法如下所示:
func loadRecordsFromiCloud() {
// Get a private Database
let privateDatabase = CloudKitManager.sharedInstance.privateDatabase
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "MyRecords", predicate: predicate)
let operation = CKQueryOperation(query: query)
privateDatabase.perform(query, inZoneWith: nil) { (results, error) in
if ((error) != nil) {
// Error handling for failed fetch from public database
print("error loading : \(error)")
}
else {
// Display the fetched records
//print(results!)
self.tableViewDataArray = results!
DispatchQueue.main.async {
print("DispatchQueue.main.sync")
self.tableView.reloadData()
}
}
}
}
有时当 CloudKit 服务器工作得更快时,我可以在 tableView 中看到新记录,但大多数时候会有延迟(我在 MainViewController 加载时看不到 tableview 中的新结果)我认为这个是因为当我获取记录时它获取旧数据(不知道为什么),但也许我又犯了一个错误。这是一个糟糕的用户体验,我想知道如何避免这种延迟。我希望我的 tableView 在我关闭 CreateRecordViewController 后立即显示更新的结果。
我的第一个想法是订阅 CloudKit Records changes ,并在收到通知时在 tableView 中获取和重新加载数据,但我真的不需要推送通知(我宁愿在代码中有一个方法,在我知道所有 CloudKit 记录已保存或之后我可以从 CloudKit 获取数据在我知道创建了一条新记录之后,在获取并获取 tableView 的数据之后,我会调用 tableView.reloadData,例如),但我不确定如何正确实现(以什么方法)并且不确定如果这是最好的解决方案。我还听说在专门针对 CloudKit 的 WWDC 2016 视频中,现在有一些与订阅记录更改相关的新方法,也许其中一些方法可以提供帮助(不确定)。为这个问题(延迟问题)寻找最好的或任何好的和简单的解决方案。
我正在使用 XCode 8、iOS 10、swift 3
最佳答案
无法保证查询中记录何时可用,但您可以做一些事情。您可以将新记录拼接回去。因为当您创建和保存记录时,您拥有记录 ID,您可以进行 ckfetchrecords 操作并从新记录传递 ID,并且您可以保证立即取回它。索引有时可能需要一段时间,这对 CloudKit 来说是令人沮丧的。因此,基本上保证快速数据库的最佳方法是进行查询,如果新记录 ID 不在其中,则使用该 ID 进行提取并将其附加到结果中。希望这是有道理的。
我之前不得不这样做,因为我不太喜欢 CK。这是将记录拼接回去的操作的链接。https://developer.apple.com/reference/cloudkit/ckfetchrecordsoperation另外,如果您正在使用图像,请查看我制作的这个库,它允许您排除图像数据 key 并按需下载和缓存,这可以加快您的查询速度。 https://github.com/agibson73/AGCKImage
评论后编辑:
我认为您没有得到的部分是,由于索引的工作方式,记录可能会或可能不会随 viewcontroller 1 中的查询一起出现。您甚至在问题中提到它会获取旧数据。这是由于服务器索引。如果您删除记录,也会发生同样的情况。它可能仍会在查询中显示一段时间。在这种情况下,您会跟踪最近删除的记录 ID 并在查询后将其删除。同样,我所说的这种手动添加和删除是保证用户看到的内容和查询结果与用户期望的保持同步的唯一方法。
这是一些代码,虽然完全未经测试,但我希望它们能帮助您形象化我上面所说的内容。
func loadRecordsFromiCloud() {
// Get a private Database
let privateDatabase = CKContainer.default().privateCloudDatabase
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "MyRecords", predicate: predicate)
privateDatabase.perform(query, inZoneWith: nil) { (results, error) in
if ((error) != nil) {
// Error handling for failed fetch from public database
print("error loading : \(error)")
}
else {
//check for a newRecord ID that might be missing from viewcontroller 2 that was passed back
if self.passedBackNewRecordID != nil{
let newResults = results?.filter({$0.recordID == self.passedBackNewRecordID})
//only excute if there is a new record that is missing from the query
if newResults?.count == 0{
//houston there is a problem
let additionalOperation = CKFetchRecordsOperation(recordIDs: [self.passedBackNewRecordID!])
additionalOperation.fetchRecordsCompletionBlock = { recordsDict,fetchError in
if let newRecords = recordsDict?.values as? [CKRecord]{
//stitch the missing record back in
let final = newRecords.flatMap({$0}) + results!.flatMap({$0})
self.reloadWithResults(results: final)
self.passedBackNewRecordID = nil
}else{
self.reloadWithResults(results: results)
self.passedBackNewRecordID = nil
}
}
privateDatabase.add(additionalOperation)
}else{
//the new record is already in the query result
self.reloadWithResults(results: results)
self.passedBackNewRecordID = nil
}
}else{
//no new records missing to do additional check on
self.reloadWithResults(results: results)
}
}
}
}
func reloadWithResults(results:[CKRecord]?){
self.tableViewDataArray = results!
DispatchQueue.main.async {
print("DispatchQueue.main.sync")
self.tableView.reloadData()
}
}
}
有点乱,但您可以看到我正在将丢失的 recordID(如果不是 nil)拼接回您正在执行的查询,因为不能保证该查询实时为您提供预期的新记录。在这种情况下,self.passedBackNewRecordID 是根据 Viewcontroller 2 中的新 recordID 设置的。如何设置或跟踪此变量取决于您,但您可能需要一个完整的队列系统,因为我告诉您的内容适用于对记录的更改以及删除。因此,在生产应用程序中,我必须跟踪有更改、删除和添加的记录,并获取每个记录的最新版本,这样你就可以想象对象列表的复杂性了。自从我停止使用 CloudKit 以来,因为逻辑删除或索引编制花费的时间太长,无法显示查询中的更改。
测试您保存的代码可能如下所示。
CloudKitManager.sharedInstance.privateDatabase.save(myRecord) { (savedRecord, error) -> Void in
if error == nil {
print("successfully saved record code: \(savedRecord)")
//save temporarily to defaults
let recordID = "someID"
UserDefaults.standard.set(recordID, forKey: "recentlySaved")
UserDefaults.standard.synchronize()
//now we can dismiss
}
else {
// Insert error handling
print("error Saving Data to iCloud: \(error.debugDescription)")
}
}
在您在 View Controller 1 中调用查询的代码中,您可能会调用 viewWillAppear
func startQuery(){
UserDefaults.standard.synchronize()
if let savedID = UserDefaults.standard.value(forKey: "recentlySaved") as? String{
passedBackNewRecordID = CKRecordID(recordName: savedID)
//now we can remove from Userdefualts
UserDefaults.standard.removeObject(forKey: "recentlySaved")
UserDefaults.standard.synchronize()
}
self.loadRecordsFromiCloud()
}
这应该非常适合您的示例,并允许您测试我所说的内容,可能只需进行微小的更改。
关于ios - 如何在创建新记录时使用 CloudKit 不延迟地更新 TableView 中的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42729601/
我有一个网站。 必须登录才能看到里面的内容。 但是,我使用此代码登录。 doc = Jsoup.connect("http://46.137.207.181/Account/Login.aspx")
我正在尝试为我的域创建一个 SPF 记录并使我的邮件服务器能够对其进行评估。我在邮件服务器上使用 Postfix 并使用 policyd-spf (Python) 来评估记录。目前,我通过我的私有(p
我需要为负载平衡的 AWS 站点 mywebsite.com 添加 CName 记录。记录应该是: @ CNAME mywebsite.us-east-1.elb.amazon
我目前正在开发一个相当大的多层应用程序,该应用程序将部署在海外。虽然我希望它在解聚后不会折叠或爆炸,但我不能 100% 确定这一点。因此,如果我知道我可以请求日志文件,以准确找出问题所在以及原因,那就
我使用以下命令从我的网络摄像头录制音频和视频 gst-launch-0.10 v4l2src ! video/x-raw-yuv,width=640,height=480,framerate=30/1
我刚刚开始使用 ffmpeg 将视频分割成图像。我想知道是否可以将控制台输出信息保存到日志文件中。我试过“-v 10”参数,也试过“-loglevel”参数。我在另一个 SO 帖子上看到使用 ffmp
我想针对两个日期查询我的表并检索其中的记录。 我这样声明我的变量; DECLARE @StartDate datetime; DECLARE @EndDate datetime; 并像这样设置我的变量
在 javascript 中,我可以使用简单的 for 循环访问对象的每个属性,如下所示 var myObj = {x:1, y:2}; var i, sum=0; for(i in myObj) s
最近加入了一个需要处理大量代码的项目,我想开始记录和可视化调用图的一些流程,让我更好地理解一切是如何组合在一起的。这是我希望在我的理想工具中看到的: 每个节点都是一个函数/方法 如果一个函数可以调用另
如何使用反射在F#中创建记录类型?谢谢 最佳答案 您可以使用 FSharpValue.MakeRecord [MSDN]创建一个记录实例,但是我认为F#中没有任何定义记录类型的东西。但是,记录会编译为
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 3年前关闭。 Improve thi
我是 Sequelize 的新手并且遇到了一些语法问题。我制作了以下模型: // User sequelize.define('user', { name: { type: DataTyp
${student.name} Notify 这是我的output.jsp。请注意,我已经放置了一个链接“Notify”以将其转发到 display.jsp 上。但我不确定如何将 Stud
例如,这是我要做的查询: server:"xxx.xxx.com" AND request_url:"/xxx/xxx/xxx" AND http_X_Forwarded_Proto:(https O
我一直在开发大量 Java、PHP 和 Python。所有这些都提供了很棒的日志记录包(分别是 Log4J、Log 或logging)。这在调试应用程序时有很大帮助。特别是当应用程序 headless
在我的Grails应用程序中,我异步运行一些批处理过程,并希望该过程记录各种状态消息,以便管理员以后可以检查它们。 我考虑过将log4j JDBC附加程序用作最简单的解决方案,但是据我所知,它不使用D
我想将进入 MQ 队列的消息记录到数据库/文件或其他日志队列,并且我无法修改现有代码。是否有任何方法可以实现某种类似于 HTTP 嗅探器的消息记录实用程序?或者也许 MQ 有一些内置的功能来记录消息?
如果我有一条包含通用字段的记录,在更改通用字段时是否有任何方法可以模仿方便的 with 语法? 即如果我有 type User = // 'photo can be Bitmap or Url {
假设我有一个名为 Car 的自定义对象。其中的所有字段都是私有(private)的。 public class Car { private String mName; private
当记录具有特定字段时,我需要返回 true 的函数,反之亦然。示例: -record(robot, {name, type=industrial, ho
我是一名优秀的程序员,十分优秀!