应用程序卸载/重新安装后,CoreData + Cloudkit fetch不会返回任何结果

如何解决应用程序卸载/重新安装后,CoreData + Cloudkit fetch不会返回任何结果

我正在尝试使用NSPersistentCloudKitContainer配置CoreData + CloudKit,以自动将数据同步到CloudKit,或从CloudKit自动同步数据。

the Apple guide之后,建立实体,在Xcode中添加适当的功能,在我的AppDelegate中设置persistentContainersaveContext都很简单。

我正在通过fetch()进行save()NSManagedObjectContext的呼叫,并且能够保存和获取记录而没有问题。我可以在CloudKit仪表板中看到它们。

但是,如果我从模拟器中卸载应用程序并重建/重新安装,我的fetchRequest(没有NSPredicate或没有排序,只是获取所有记录)总是返回一个空列表。我使用的是相同的iCloud帐户,并且尝试了公共数据库范围和私有数据库范围。如果我创建一个新记录,然后重试获取请求,则可以检索该新创建的记录,但不能检索任何旧记录。我100%肯定这些记录仍在CloudKit数据库中,因为我可以在CloudKit Dashboard Web应用程序上看到它们。

我看过Apple's CoreDataCloudKitDemo应用程序,它能够在卸载/重新安装后从CloudKit数据库中获取“发布”实体,因此我知道这是可能的。但是,它使用的是NSFetchedResultsController,不适用于我的应用程序(我的游戏是SpriteKit游戏)。

我尝试将CoreData + Cloudkit代码复制到全新的Xcode项目中,并且可以在此处重现此问题。这是我的代码供参考:

import UIKit
import CoreData

@main
class AppDelegate: UIResponder,UIApplicationDelegate {

    lazy var persistentContainer: NSPersistentContainer = {

        // Create a container that can load CloudKit-backed stores
        let container = NSPersistentCloudKitContainer(name: "coredatacloudkitexample")

        // Enable history tracking and remote notifications
        guard let description = container.persistentStoreDescriptions.first else {
            fatalError("###\(#function): Failed to retrieve a persistent store description.")
        }
        description.setOption(true as NSNumber,forKey: NSPersistentHistoryTrackingKey)
        description.setOption(true as NSNumber,forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        description.cloudKitContainerOptions?.databaseScope = .public

        container.loadPersistentStores(completionHandler: { (_,error) in
            guard let error = error as NSError? else { return }
            fatalError("###\(#function): Failed to load persistent stores:\(error)")
        })

        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        container.viewContext.transactionAuthor = "nibbler"

        // Pin the viewContext to the current generation token and set it to keep itself up to date with local changes.
        container.viewContext.automaticallyMergesChangesFromParent = true
        do {
            try container.viewContext.setQueryGenerationFrom(.current)
        } catch {
            fatalError("###\(#function): Failed to pin viewContext to the current generation:\(error)")
        }

        return container
    }()
}


// ------

import UIKit
import CoreData

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let viewContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
        let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()
        let people: [Person]

        do {
            people = try viewContext.fetch(fetchRequest)
            print("---> fetched People from CoreData: \(people)")

            // people.isEmpty is ALWAYS true (empty array) on first install of app,even if records exist in table in CloudKit
            if people.isEmpty {
                let person = Person(context: viewContext)
                person.name = "nibbler"

                // save the data through managed object context
                do {
                    try viewContext.save()
                    print("--> created Person in CoreData: \(person)")
                } catch {
                    print("---> failed to save Person: \(error.localizedDescription)")
                }
            }
        } catch {
            print("---> error: \(error)")
        }
    }
}


我想念什么?为什么我只能提取在此应用的安装过程中创建的记录,而不能提取以前的记录?

更新:看来,如果我等待几秒钟,然后尝试重新安装我上午能够从CloudKit数据库。首次启动时,我也可以在控制台中看到大量CoreData+CloudKit日志消息。这就是我的想法-即使使用NSPersistentCloudKitContainer时,fetch()也在读/写本地CoreData存储,然后在后台运行一个单独的进程来镜像和合并本地CoreData记录与CloudKit记录。

这样,我认为我需要以某种方式等待/被通知,本地CoreData和CloudKit记录的这种同步/合并已在首次启动之前完成,然后进行了fetch()调用,而不是进行{{1} }在应用打开时立即调用。有什么想法吗?

解决方法

您需要使用NSFetchedResultsController,为什么您认为它不适用于您的应用?

NSFetchedResultsController监视viewContext是必要的原因,并且当同步过程下载新对象并将其插入到后台上下文中时,automaticallyMergesChangesFromParent会将这些对象合并到{{ 1}},并推进生成令牌。调用FRC的委托方法来通知您是否从获取的对象数组中插入,更新或删除了对象,这些对象是上下文中与获取请求实体和谓词相匹配的对象。

,

您可以尝试的是这样:

  • 设置NSPersistentCloudKitContainerOptions
let id = "iCloud.yourid"  
let options = NSPersistentCloudKitContainerOptions(containerIdentifier: id)  
description?.cloudKitContainerOptions = options
  • 初始化您的CloudKit模式(至少需要一次)
do {
     try container.initializeCloudKitSchema()
  } catch {
    print("ERROR \(error)")
 }

编辑:
您可以更改lazy var persistentContainer: NSPersistentContainer

lazy var persistentContainer: NSPersistentCloudKitContainer

,

这是@professormeowingtons,您在模拟器上删除该应用程序时不会提及之前的记录,因此我建议您在已配置iCloud帐户的真实设备上尝试该应用程序,这样'将能够向数据库中添加一些记录,然后删除该应用程序,重新安装并获取您输入的所有先前记录。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-