如何使用 NSFetchRequest 和 fetchLimit = 1 从核心数据中获取 0 或 1 个实体?

How to fetch 0 or 1 entity with NSFetchRequest and fetchLimit = 1 from Core Data?

在多语言应用程序中,我让用户通过 Sign In with Apple、Google 或 Facebook 登录,然后将他们的数据(用户 ID、名字、姓氏等)存储到 UserEntity:

创建实体时,我将 stamp 属性设置为当前纪元秒数。

然后在我的自定义视图模型中,我尝试使用以下代码获取至少一个用户并将其分配给 @Published var,以便我的应用知道用户是否已经登录:

class UserViewModel: ObservableObject {
    @Published var myUser: UserEntity?

    init(language: String) {
        fetchMyUser(language: language)
    }
    
    func fetchMyUser(language:String) {
        print("fetchMyUser language=\(language)")
        guard let container = PersistenceController.shared[language]?.container else { return }
        let request = NSFetchRequest<UserEntity>(entityName: "UserEntity")
        request.sortDescriptors = [ NSSortDescriptor(keyPath: \UserEntity.stamp, ascending: false) ]
        request.fetchLimit = 1
        
        do {
            myUser = try container.viewContext.fetch(request)[0]
        } catch let error {
            print("fetchMyUser fetch error: \(error)")
        }
    }
}

注意:请忽略language字符串参数(“en”、“de”或“ru”)。它被用来select对应NSPersistentContainer。此代码有效,与我的问题无关。

我的问题是,当容器中还没有实体(用户从未登录)时,do/try/catch 代码失败并显示 Fatal error: Index out of range

不应该 do/try/catch 只捕获这个异常,为什么我的应用程序崩溃以及如何修复我的代码,以便获取 0 或 1 UserEntity 并将其分配给 myUser

Swift 中的 do/try/catch 机制捕获 Errors,它们在其他地方是 thrown,详情参见 Error Handling。它不是一般的异常处理机制。

特别地,“索引越界”是一个运行时错误并且无法被捕获。它总是会立即终止程序。

如果无法执行提取请求,

viewContext.fetch(request) 将引发错误。否则它 return 是一个数组或 零个或多个 个对象。为了检查(至少)一个对象是否被 returned,您必须检查 return 数组的 countisEmpty 属性。

另一种选择(如评论中所述)是使用 first 属性,其中 return 是 Optional:第一个元素(如果数组不为空),或 nil。在你的情况下是

do {
    myUser = try container.viewContext.fetch(request).first
} catch let error {
    print("fetchMyUser fetch error: \(error)")
}