微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何修改实体的核心数据属性,但在我的数据库的所有元素上 解包可选的 .first 值检查索引处的值是否存在

如何解决如何修改实体的核心数据属性,但在我的数据库的所有元素上 解包可选的 .first 值检查索引处的值是否存在

你好社区我是新手,这是我的第一个问题。 如何更改实体的所有属性并能够更改我的所有核心数据元素, 因为我只能更改实体的第一个属性,而不能更改所有数据记录。

在这函数里我只能改名字 然后我收到以下错误行

let objectUpdate = test[0] : Thread 1: Fatal error: Index out of range

func updateData() {

    var newName = ""
    var newPrenom = ""

    newName = name.text!
    newPrenom = prenom.text!

    let managedContext =  AppDelegate.viewContext
    let fetchRequest : NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "Person")
    fetchRequest.predicate = nspredicate(format: "name = %@",newName)
    do {
        fetchRequest.predicate = nspredicate(format: "prenom = %@",newPrenom)

        let test = try! managedContext.fetch(fetchRequest) as! [NSManagedobject]
        let objectUpdate = test[0]

        objectUpdate.setValue(newName,forKey: "name")
        objectUpdate.setValue(newPrenom,forKey: "prenom")
        do {
            try managedContext.save()
        }
        catch {
            print(error)
        }
    } catch {
        print(error)
    }
}

解决方法

有多种方法可以避免此错误。

解包可选的 .first

Swift 的 Collection 为我们提供了获取第一项的安全方法,只需访问给定集合的 first 属性即可。它将返回一个 Optional<Element> 值,因此我们需要先使用 if let of guard let

解开它
if let object = test.first {
    // do something with object
}

guard let object = test.first else { return }
// do something with object

检查索引处的值是否存在

在访问 indices 属性中的特定索引之前检查其背后的值通常是个好主意。

if test.indices.contains(0) {
    let object = test[0]
    // do something with object
}

这些提示应该可以防止您的代码再次崩溃。

其他建议

这并不安全或干净:

var newName = ""
var newPrenom = ""

newName = name.text!
newPrenom = prenom.text!

我们可以通过使用 guard 语句使其更简洁,最重要的是更安全

guard let newName = name.text,let newPrenom = prenom.text else { return }

这里发生了两件重要的事情:

  1. 不再强制解包 text 的可选值 [这可能会导致崩溃]
  2. 属性现在是不可变的,这意味着我们可以确定我们保存到 CoreDate 的内容是在函数开始时检索到的内容

自行:

let test = try! managedContext.fetch(fetchRequest) as! [NSManagedObject]

已经包含在 do-catch 子句中,您可以安全地移除强制 try! 并将其替换为 try

let test = try managedContext.fetch(fetchRequest) as! [NSManagedObject]

让我们使用类型!在这一行中,您为某个名为 NSFetchRequest 的实体创建了一个 "Person" 对象。

let fetchRequest : NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "Person")

我猜 CoreData 已经为你生成了一个名为 NSManagedObjectPerson 子类。如果这是真的,你可以像这样重写它:

let fetchRequest = NSFetchRequest<Person>(entityName: "Person")

实现上一个技巧后,我们现在可以去掉这一行中的 as! [NSManagedObject]

let test = try managedContext.fetch(fetchRequest) as! [NSManagedObject]

既然 NSFetchRequest 对象现在已经很好地类型化了,我们可以通过像这样重写它来利用它:

let test: [Person] = try managedContext.fetch(fetchRequest)

所以我们现在使用正确的类型?凉爽的!现在让我们改进一下:

objectUpdate.setValue(newName,forKey: "name")
objectUpdate.setValue(newPrenom,forKey: "prenom")

通过重写它并使用 Person 对象上的属性

objectUpdate.name = newName
objectUpdate.prenom = newPrenom

无需再引入第二层的 do-catch 子句,因为我们已经合二为一了!

do {
    try managedContext.save()
}
catch {
    print(error)
}

您可以轻松地用 save() 调用替换它,如下所示:

try managedContext.save()

您确定这些谓词是您想要的吗?

fetchRequest.predicate = NSPredicate(format: "name = %@",newName)
fetchRequest.predicate = NSPredicate(format: "prenom = %@",newPrenom)

我可以从它们中了解到您正在获取名称为 Person 且 prenom 为 newNamenewPrenom 对象,然后您使用相同的确切值对其进行更新?您是否使用某种用户身份识别?比如id: Int还是id: UUID?写这样的东西会更有意义

let id: Int = // ID of the user you are currently editing 
fetchRequest.predicate = NSPredicate(format: "id == \(id)")

如果您没有使用任何 id,您可以尝试存储 nameprenom 的初始值

// in cell declaration - set when you configure your cell
var initialName: String?
var initialPrenom: String? 
// then in your function:
fetchRequest.predicate = NSPredicate(format: "name = %@",initialName)
fetchRequest.predicate = NSPredicate(format: "prenom = %@",initialPrenom)

但我刚刚注意到您还用第二个谓词覆盖了第一个谓词。您需要使用 NSCompoundPredicate

fetchRequest.predicate = NSCompoundPredicate(
    type: .and,subpredicates: [
        NSPredicate(format: "name = %@",initialName),NSPredicate(format: "prenom = %@",initialPrenom)
    ]
)

建议版本

func updateData() {
    guard let newName = name.text,let newPrenom = prenom.text else { return }
    let managedContext = AppDelegate.viewContext
    let fetchRequest = NSFetchRequest<Person>(entityName: "Person")

    fetchRequest.predicate = NSCompoundPredicate(
        type: .and,subpredicates: [
            NSPredicate(format: "name = %@",initialPrenom)
        ]
    )
    do {
        let objects: [Person] = try managedContext.fetch(fetchRequest)
        guard let object = objects.first else { return }
        object.name = newName
        object.prenom = newPrenom
        try managedContext.save()
    } catch {
        print(error)
    }
}
,

如果索引 0 超出范围,则表示数组为空。在访问它之前,添加

if test.isEmpty{
   return //the fetch request didn't return any values
}

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