检索实体名称时崩溃?
Crash on retrieving entity name?
当我的应用程序首次启动时,我会进行一些首次设置配置,即使用 CoreData API 和 JSON 文档中的数据为我的 SQLLite 数据库播种。
我首先从我的核心数据堆栈中获取对我的托管对象上下文的引用,然后调用一个执行 JSON 配置的方法。然后我打电话:
....(JSON conversion)....
context.perform {
_ = Exercise.insert(into: context, name: exerciseName, category: categoryNumber, equipment: equipment, skill: "", primaryMuscle: primaryMuscle, otherMuscles: otherMuscles, info: exerciseDescription, image1: exerciseImage1, image2: exerciseImage2)
}
在我遍历 JSON 个对象的每次迭代中,它会保留每个对象。
插入对象的方法是这样的:
public static func insert(into context: NSManagedObjectContext, name: String, category: Int16, equipment: String?, skill: String?, primaryMuscle: String?, otherMuscles: String?, info: String?, image1: String?, image2: String?) -> Exercise {
let exercise: Exercise = context.insertObject()
exercise.name = name
exercise.category = category
exercise.info = info
exercise.primaryMuscle = primaryMuscle
exercise.otherMuscles = otherMuscles
exercise.equipment = equipment
exercise.skill = skill
if image1 != nil {
exercise.image1Path = image1
}
if image2 != nil {
exercise.image2Path = image2
}
return exercise
}
然后我扩展了 NSManagedObjectContext...
extension NSManagedObjectContext {
public func insertObject<Object: NSManagedObject>() -> Object where Object: Managed {
guard let obj = NSEntityDescription.insertNewObject(forEntityName: Object.entityName, into: self) as? Object else { fatalError("Wrong object type") }
return obj
}
}
这是我的 "Managed" 协议声明:
public protocol Managed: class, NSFetchRequestResult {
static var entityName: String {get}
....
}
extension Managed where Self: NSManagedObject {
public static var entityName: String { return entity().name! }
}
然后当我尝试从我试图插入对象的协议扩展中检索 entityName 时崩溃...
它给我错误 "fatal error: unexpectedly found nil while unwrapping an Optional value"
我没有生成我的 NSManagedObjectSublcasses,我自己创建了它们,但我确信我做对了。我有一种感觉,虽然当应用程序运行时,Core Data 没有为 "Exercise" 选择我的模型 class。这就是实体名称不返回任何内容的原因。所以这是我的模型代码 class:
import UIKit
import CoreData
public class Exercise: NSManagedObject {
@NSManaged public fileprivate(set) var category: Int16
@NSManaged public fileprivate(set) var image1Path: String?
@NSManaged public fileprivate(set) var image2Path: String?
@NSManaged public fileprivate(set) var equipment: String?
@NSManaged public fileprivate(set) var info: String?
@NSManaged public fileprivate(set) var skill: String?
@NSManaged public fileprivate(set) var primaryMuscle: String?
@NSManaged public fileprivate(set) var otherMuscles: String?
public static let normalizedNameKey = "name_normalized"
@NSManaged fileprivate var primitiveName: String
public var name: String {
set {
willChangeValue(forKey: #keyPath(Exercise.name))
primitiveName = newValue
updateNormalizedName(newValue)
didChangeValue(forKey: #keyPath(Exercise.name))
}
get {
willAccessValue(forKey: #keyPath(Exercise.name))
let value = primitiveName
didAccessValue(forKey: #keyPath(Exercise.name))
return value
}
}
fileprivate func updateNormalizedName(_ name: String) {
setValue(name.normalizedForSearch, forKey: Exercise.normalizedNameKey)
}
public var exerciseImage1: UIImage? {
guard let image = image1Path else {return nil}
return UIImage(named: image)
}
public var exerciseImage2: UIImage? {
guard let image = image2Path else {return nil}
return UIImage(named: image)
}
public static func insert(into context: NSManagedObjectContext, name: String, category: Int16, equipment: String?, skill: String?, primaryMuscle: String?, otherMuscles: String?, info: String?, image1: String?, image2: String?) -> Exercise {
let exercise: Exercise = context.insertObject()
exercise.name = name
exercise.category = category
exercise.info = info
exercise.primaryMuscle = primaryMuscle
exercise.otherMuscles = otherMuscles
exercise.equipment = equipment
exercise.skill = skill
if image1 != nil {
exercise.image1Path = image1
}
if image2 != nil {
exercise.image2Path = image2
}
return exercise
}
}
extension Exercise: Managed {
public static var defaultSortDescriptors: [NSSortDescriptor] {
return [NSSortDescriptor(key: #keyPath(name), ascending: false)]
}
public static func defaultPredicate(muscleCategory: Int) -> NSPredicate
{
return NSPredicate(format: "%K == %ld",
#keyPath(Exercise.category), muscleCategory)
}
}
这是数据模型编辑器中的实体:
知道哪里出了问题吗?谢谢
莫因,
首先展开可选值。
public static var entityName: String
{
if let _returnName = entity().name{
return _returnName
}else
{
return nil
}
}
}
核心数据:
Class 运动
当您更改 dbModel 并执行 "Create NSManagedObject Sub.." 练习中的所有函数都将被覆盖。
使用单独的 class,例如 class ExerciseExtension
import UIKit
import CoreData
extension Exercise {
func setName(name : String)
{
self.name = name
}
.....
}
也许这不是一个好主意,但现在可以避免崩溃...等待更好的解决方案。
swift 4:
extension NSObject {
var className: String {
return String(describing: type(of: self))
}
class var className: String {
return String(describing: self)
}
}
然后
static var entityName: String {
return self.className //insead of `entity().name!`
}
我有完全相同的问题,使用完全相同的代码(Florian Kugler 的核心数据书)。
我的问题出现在我添加了一个新的实体+关系,并且在创建新实体时,实体名称为零。
我通过删除实体并再次重新创建来修复它。并且错误消失了。
我在 Swift 4.1 项目上遇到了类似的问题,Xcode 9.4.1 在 iOS 10.3+ 上
我试图做类似的事情:
guard let description = Entity.entity(),
throw Error.entityNotFound
}
*[some code]*
context.perform {
*[some code]*
}
但是我的一些单元测试失败了,其他的则运行良好。我的 xcdatamodel
和 NSManagedObject
子类非常好。
最后,我通过检索 perform
闭包中的实体名称使其工作:
context.perform {
guard let description = Entity.entity(),
throw Error.entityNotFound
}
*[some code]*
}
我在 Florian Kugler 的核心数据书中也遇到了同样的问题。不幸的是@Kobe 的回答没有帮助。
我通过在我的核心数据模型的文件检查器中为 Class 选择模块解决了这个问题。
之前设置为'none'。
当我的应用程序首次启动时,我会进行一些首次设置配置,即使用 CoreData API 和 JSON 文档中的数据为我的 SQLLite 数据库播种。
我首先从我的核心数据堆栈中获取对我的托管对象上下文的引用,然后调用一个执行 JSON 配置的方法。然后我打电话:
....(JSON conversion)....
context.perform {
_ = Exercise.insert(into: context, name: exerciseName, category: categoryNumber, equipment: equipment, skill: "", primaryMuscle: primaryMuscle, otherMuscles: otherMuscles, info: exerciseDescription, image1: exerciseImage1, image2: exerciseImage2)
}
在我遍历 JSON 个对象的每次迭代中,它会保留每个对象。
插入对象的方法是这样的:
public static func insert(into context: NSManagedObjectContext, name: String, category: Int16, equipment: String?, skill: String?, primaryMuscle: String?, otherMuscles: String?, info: String?, image1: String?, image2: String?) -> Exercise {
let exercise: Exercise = context.insertObject()
exercise.name = name
exercise.category = category
exercise.info = info
exercise.primaryMuscle = primaryMuscle
exercise.otherMuscles = otherMuscles
exercise.equipment = equipment
exercise.skill = skill
if image1 != nil {
exercise.image1Path = image1
}
if image2 != nil {
exercise.image2Path = image2
}
return exercise
}
然后我扩展了 NSManagedObjectContext...
extension NSManagedObjectContext {
public func insertObject<Object: NSManagedObject>() -> Object where Object: Managed {
guard let obj = NSEntityDescription.insertNewObject(forEntityName: Object.entityName, into: self) as? Object else { fatalError("Wrong object type") }
return obj
}
}
这是我的 "Managed" 协议声明:
public protocol Managed: class, NSFetchRequestResult {
static var entityName: String {get}
....
}
extension Managed where Self: NSManagedObject {
public static var entityName: String { return entity().name! }
}
然后当我尝试从我试图插入对象的协议扩展中检索 entityName 时崩溃...
它给我错误 "fatal error: unexpectedly found nil while unwrapping an Optional value"
我没有生成我的 NSManagedObjectSublcasses,我自己创建了它们,但我确信我做对了。我有一种感觉,虽然当应用程序运行时,Core Data 没有为 "Exercise" 选择我的模型 class。这就是实体名称不返回任何内容的原因。所以这是我的模型代码 class:
import UIKit
import CoreData
public class Exercise: NSManagedObject {
@NSManaged public fileprivate(set) var category: Int16
@NSManaged public fileprivate(set) var image1Path: String?
@NSManaged public fileprivate(set) var image2Path: String?
@NSManaged public fileprivate(set) var equipment: String?
@NSManaged public fileprivate(set) var info: String?
@NSManaged public fileprivate(set) var skill: String?
@NSManaged public fileprivate(set) var primaryMuscle: String?
@NSManaged public fileprivate(set) var otherMuscles: String?
public static let normalizedNameKey = "name_normalized"
@NSManaged fileprivate var primitiveName: String
public var name: String {
set {
willChangeValue(forKey: #keyPath(Exercise.name))
primitiveName = newValue
updateNormalizedName(newValue)
didChangeValue(forKey: #keyPath(Exercise.name))
}
get {
willAccessValue(forKey: #keyPath(Exercise.name))
let value = primitiveName
didAccessValue(forKey: #keyPath(Exercise.name))
return value
}
}
fileprivate func updateNormalizedName(_ name: String) {
setValue(name.normalizedForSearch, forKey: Exercise.normalizedNameKey)
}
public var exerciseImage1: UIImage? {
guard let image = image1Path else {return nil}
return UIImage(named: image)
}
public var exerciseImage2: UIImage? {
guard let image = image2Path else {return nil}
return UIImage(named: image)
}
public static func insert(into context: NSManagedObjectContext, name: String, category: Int16, equipment: String?, skill: String?, primaryMuscle: String?, otherMuscles: String?, info: String?, image1: String?, image2: String?) -> Exercise {
let exercise: Exercise = context.insertObject()
exercise.name = name
exercise.category = category
exercise.info = info
exercise.primaryMuscle = primaryMuscle
exercise.otherMuscles = otherMuscles
exercise.equipment = equipment
exercise.skill = skill
if image1 != nil {
exercise.image1Path = image1
}
if image2 != nil {
exercise.image2Path = image2
}
return exercise
}
}
extension Exercise: Managed {
public static var defaultSortDescriptors: [NSSortDescriptor] {
return [NSSortDescriptor(key: #keyPath(name), ascending: false)]
}
public static func defaultPredicate(muscleCategory: Int) -> NSPredicate
{
return NSPredicate(format: "%K == %ld",
#keyPath(Exercise.category), muscleCategory)
}
}
这是数据模型编辑器中的实体:
知道哪里出了问题吗?谢谢
莫因,
首先展开可选值。
public static var entityName: String
{
if let _returnName = entity().name{
return _returnName
}else
{
return nil
}
}
}
核心数据:
Class 运动
当您更改 dbModel 并执行 "Create NSManagedObject Sub.." 练习中的所有函数都将被覆盖。
使用单独的 class,例如 class ExerciseExtension
import UIKit
import CoreData
extension Exercise {
func setName(name : String)
{
self.name = name
}
.....
}
也许这不是一个好主意,但现在可以避免崩溃...等待更好的解决方案。
swift 4:
extension NSObject {
var className: String {
return String(describing: type(of: self))
}
class var className: String {
return String(describing: self)
}
}
然后
static var entityName: String {
return self.className //insead of `entity().name!`
}
我有完全相同的问题,使用完全相同的代码(Florian Kugler 的核心数据书)。
我的问题出现在我添加了一个新的实体+关系,并且在创建新实体时,实体名称为零。
我通过删除实体并再次重新创建来修复它。并且错误消失了。
我在 Swift 4.1 项目上遇到了类似的问题,Xcode 9.4.1 在 iOS 10.3+ 上 我试图做类似的事情:
guard let description = Entity.entity(),
throw Error.entityNotFound
}
*[some code]*
context.perform {
*[some code]*
}
但是我的一些单元测试失败了,其他的则运行良好。我的 xcdatamodel
和 NSManagedObject
子类非常好。
最后,我通过检索 perform
闭包中的实体名称使其工作:
context.perform {
guard let description = Entity.entity(),
throw Error.entityNotFound
}
*[some code]*
}
我在 Florian Kugler 的核心数据书中也遇到了同样的问题。不幸的是@Kobe 的回答没有帮助。 我通过在我的核心数据模型的文件检查器中为 Class 选择模块解决了这个问题。
之前设置为'none'。