在核心数据

时间:2017-10-05 19:39:15

标签: swift xcode core-data

我有一个连接到Storyboard GUI的核心数据模型。(Xcode 9和SWIFT 4)我现在想要添加一个源自另外两个属性的属性。我有一个名为Workout的实体,它的两个属性“rpe”和“秒”组合起来创建一个新属性“rpeTSS”。我在我的核心数据模型中声明了“repTSS”作为属性。我把它设置为瞬态。

我尝试在编辑器菜单下使用“make NSManagedObject subclass ...”选项,但这似乎产生了有错误的文件。我尝试了子类化生成的Workout类,但无法弄清楚如何将其绑定到GUI中。

然后我对Workout进行了扩展:

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更新。

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

3 个答案:

答案 0 :(得分: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
    }
}

答案 1 :(得分:1)

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

我有一个名为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

}

人+ 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()

答案 2 :(得分: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
        }
}