如何解决如何修改实体的核心数据属性,但在我的数据库的所有元素上 解包可选的 .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 }
这里发生了两件重要的事情:
- 不再强制解包
text
的可选值 [这可能会导致崩溃] - 属性现在是不可变的,这意味着我们可以确定我们保存到 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 已经为你生成了一个名为 NSManagedObject
的 Person
子类。如果这是真的,你可以像这样重写它:
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 为 newName
的 newPrenom
对象,然后您使用相同的确切值对其进行更新?您是否使用某种用户身份识别?比如id: Int
还是id: UUID
?写这样的东西会更有意义
let id: Int = // ID of the user you are currently editing
fetchRequest.predicate = NSPredicate(format: "id == \(id)")
如果您没有使用任何 id,您可以尝试存储 name
和 prenom
的初始值
// 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 举报,一经查实,本站将立刻删除。