【问题标题】:Crash on retrieving entity name?检索实体名称时崩溃?
【发布时间】:2017-11-18 20:33:54
【问题描述】:

当我的应用程序首次启动时,我会进行一些首次设置配置,即使用 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
}
}

这是我对“托管”协议的声明:

public protocol Managed: class, NSFetchRequestResult {
static var entityName: String {get}
....
   }

extension Managed where Self: NSManagedObject {
public static var entityName: String { return entity().name! }
 }

然后,当我尝试从我尝试插入对象的协议扩展中检索 entityName 时崩溃...

它给了我错误“致命错误:在展开可选值时意外发现 nil”

我没有生成我的 NSManagedObjectSublcasses,我自己创建了它们,但我确信我做对了。我有一种感觉,当应用程序运行时,Core Data 并没有为“锻炼”选择我的模型类。这就是实体名称不返回任何内容的原因。所以这是我的模型类的代码:

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)
}
}

这是数据模型编辑器中的实体:

有什么想法可能会出错吗?谢谢

【问题讨论】:

  • 同样的问题,在 entity().name 处崩溃!
  • @hstdt:删除并重新创建。这解决了我的问题。

标签: xcode sqlite core-data nsmanagedobject swift-protocols


【解决方案1】:

莫恩,

首先解开可选值。

    public static var entityName: String 
    { 
        if let _returnName = entity().name{
            return _returnName
        }else
        {
            return nil
        } 
   }
}

Optional Chaining

核心数据:

课堂练习

当您更改 dbModel 并执行“创建 NSManagedObject Sub..”时,练习中的所有函数都将被覆盖。

使用单独的类,例如 ExerciseExtension

import UIKit
import CoreData

extension Exercise {
  func setName(name : String)
  {
    self.name = name
  }
  .....
}

【讨论】:

  • 感谢您的回复。但是我不让 xCode 自动为我生成子类,我自己编写它们,所以我可以完全控制正在发生的事情。问题是我编写的类和数据模型之间的某个地方可能缺少链接。
【解决方案2】:

也许这不是一个好主意,但它现在可以避免崩溃......等待更好的解决方案。

迅速 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!`
}

【讨论】:

    【解决方案3】:

    我遇到了完全相同的问题,使用完全相同的代码(Florian Kugler 的核心数据书)。

    我的问题出现在我添加了一个新实体 + 关系之后,并且在创建新实体时,实体名称为 nil。
    我通过删除实体并重新创建它来修复它。并且错误消失了。

    【讨论】:

      【解决方案4】:

      我在 iOS 10.3+ 上使用 Xcode 9.4.1 的 Swift 4.1 项目中遇到了类似的问题 我试图做这样的事情:

          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]*
          }
      

      【讨论】:

        【解决方案5】:

        我在 Florian Kugler 的 Core Data 书中也遇到了同样的问题。不幸的是,@Kobe 的回答没有帮助。 我通过在我的核心数据模型的文件检查器中选择类的模块解决了这个问题。

        之前设置为“无”。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-02
          • 2017-11-02
          • 2019-08-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-11
          相关资源
          最近更新 更多