【问题标题】:Creating a calculated property in Core Data在 Core Data 中创建计算属性
【发布时间】:2017-10-05 19:39:15
【问题描述】:

我有一个连接到 Storyboard GUI 的核心数据模型。(Xcode 9 和 SWIFT 4)我现在想添加一个从其他两个派生的属性。我有一个名为 Workout 的实体,它的两个属性“rpe”和“seconds”组合在一起创建了一个新属性“rpeTSS”。我已将“repTSS”声明为我的核心数据模型中的一个属性。我已将其设置为瞬态。

我曾尝试使用编辑器菜单下的“制作 NSManagedObject 子类...”选项,但这似乎会生成带有错误的文件。我尝试对生成的 Workout 类进行子类化,但不知道如何将其绑定到 GUI。

然后我对锻炼进行了扩展:

extension Workout{

    public override func value(forKey key: String) -> Any? {
        if key == "rpeTSS"{
            return (100/49)*rpe*rpe*Double(seconds)/3600
        }else{return super.value(forKey: key)}
    }
}

老实说,这“感觉”不太对。无论如何,它(有点)有效。我现在确实得到了 rpeTSS 的正确值,它显示在我的 gui 中。但是,如果我对 rpe 和/或秒数进行更改,则 GUI 不会更新。

我猜上面的方法有点小技巧,因此绕过了各种让 GUI 更新的消息传递。

在核心数据中添加派生属性的正确方法是什么?我试图以某种方式实现这一点,这意味着如果我向我的数据模型添加任何内容,我不必为派生属性重写代码。

【问题讨论】:

  • 你能创建一个实体类的对象并在那里设置属性吗?然后,每当您更改 rpe 或 seconds 时,也会更新 rpeTSS 属性。
  • 不确定您的意思。 Entity 类是在 XCode 中自动生成的。我尝试对它进行子类化,但遇到了两个问题 - 1. 如何使 ManagedObject 成为我的子类的实例并绑定到 GUI 中的子类;和 2. 我不断收到错误消息,指出我的计算属性不符合键值。

标签: swift xcode core-data


【解决方案1】:

我想出的最终解决方案看起来和感觉都是正确的。它需要覆盖 keyPathsForValuesAffectingValue(forKey:) 如下:

extension Workout{

    @objc dynamic var rpeTSS: Double{
        return (100/49)*rpe*rpe*Double(seconds)/3600
    }

    override public class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String>{
        let keyPaths = super.keyPathsForValuesAffectingValue(forKey: key)
        switch key {
        case "rpeTSS":
            return keyPaths.union(Set(["seconds","rpe"]))
        default:
            return keyPaths
        }
}

【讨论】:

  • 我认为您不允许在扩展名中存储变量吗?
  • 你不是。此解决方案没有任何存储变量。这是我的一个旧帖子。现在了解更多,并且非常确定这是做我想做的事情的正确方法
  • 感谢 Steven Lord 提供的有趣解决方案。我面临着基于 2 个 CoreData 属性计算属性的类似需求,然后我在 SortDescriptor 中使用这些属性。到目前为止,我还没有让它工作:我收到错误“在实体中找不到密钥路径状态”。我在排序描述符中提供了关键路径\MyEntity.computedProperty,它被自动完成识别,但仍然引发错误。我会很好奇你如何使用你的财产,如果你知道为什么它在我的案例中失败了。
  • 我以前没有见过这个错误。我主要使用此功能,以便当用户编辑基础值时 GUI 会发生变化。这些属性用于通过数组控制器 sortDescriptors 进行排序的表中
  • @StevenLord 您是否必须在更新反映在您的 GUI 中之前保存上下文?或者,例如,只是设置一个基础属性 (rpe = 3) 足以触发更新的 GUI?
【解决方案2】:

仍然不确定这是正确的方法,但它确实解决了所提出的问题。但是,如果有一种“正确”的方式来做我正在尝试的事情,我会很感兴趣。

我设法通过覆盖我的扩展程序中的 setValue(:forKey) 方法来更新它:

extension Workout{

    public override func value(forKey key: String) -> Any? {
        if key == "rpeTSS"{
            if rpeTSS == 0{
                self.rpeTSS = (100/49)*rpe*rpe*Double(seconds)/3600
            }
        return rpeTSS
        }
        return super.value(forKey: key)
    }

    public override func setValue(_ value: Any?, forKey key: String) {
        super.setValue(value, forKey: key)
        if (key == "rpe") || (key == "seconds") {
            self.rpeTSS = calculateRPETSS()
        }
    }

    func calculateRPETSS() -> Double{
        return (100/49)*rpe*rpe*Double(seconds)/3600
    }
}

【讨论】:

    【解决方案3】:

    不确定这是不是你的意思,但是...

    我有一个名为Person 的实体类。这是我的两个课程:

    Person+CoreDataProperties.swift:

    extension Person {
    
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Total> {
        return NSFetchRequest<Person>(entityName: "Person")
    }
    
    @NSManaged public var name: String?
    @NSManaged public var age: Int
    
    }
    

    Person+CoreDataClass.swift:

    @objc(Person)
    public class Total: NSManagedObject {
    
    }
    

    这些是由 Xcode 生成的。然后在我的ViewController 中,当我想使用这个类时,我使用:

    var curPerson: Person?
    let personEntity = NSEntityDescription.entity(forEntityName: "Person", in: Singleton.s.context)!
    
    Singleton.s.people = try Singleton.s.context.fetch(Person.fetchRequest())
    
    // find the current person
    for p in Singleton.s.people {
        if p.name == curName { // got it
            curPerson = p
            break
        }
    }
    

    现在我有一个要操作的Person 对象。要制作我使用的新对象:

    let newPerson = Person(entity: personEntity, insertInto: Singleton.s.context)

    为了确保我的更改得到保存,我使用:

    (UIApplication.shared.delegate as! AppDelegate).saveContext()

    【讨论】:

    • 谢谢。这给了我一些思考。在我的例子中,我使用 GUI 和数组控制器中的绑定来创建我的对象。所以目前我没有实例化我的实体实例。我试图保持这种方式
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    相关资源
    最近更新 更多