CoreData Swift and transient attribute getters

2019-01-10 23:25发布

问题:

Any advice on implementing calculated attributes when using Core Data in Swift?

with the generated ManagedObject class, I tried to override the getter but I get the error:

'NSManaged' not allowed on computed properties

which implies you cannot override the getter for a transient (calculated) attribute.

In the code sample below, dateDue is defined as a transient attribute in my model.

Please note that the @NSManaged lines were generated by Xcode - not added by me.

@NSManaged var timeStamp: NSDate
@NSManaged var dateDue: String { 
    get {

        self.willAccessValueForKey("dateDue")
        var ddtmp  = self.primitiveValueForKey("dateDue") as String?
        self.didAccessValueForKey("dateDue")

        if (ddtmp == nil)
        {

            let calendar = NSCalendar.currentCalendar()

            let components = calendar.components((NSCalendarUnit.YearCalendarUnit | NSCalendarUnit.MonthCalendarUnit ) , fromDate: self.timeStamp)
            ddtmp = "\(components.year * 1000 + components.month)"
            self.setPrimitiveValue(ddtmp, forKey: "dateDue")

        }



        return ddtmp!
    }

}

回答1:

First, in the data model create a transient attribute (section). Because it is transient, it is not physically stored and thus not stored in the managed object context.

The section attribute is shown here:

The entity is shown here:

The class NSManagedObject subclass should have computed 'section' attribute. The NSManagedObject subclass demonstrating how to accomplish this is shown here:

class Number: NSManagedObject {

    @NSManaged var number: NSNumber

    var section: String? {
        return number.intValue >= 60 ? "Pass" : "Fail"
    }
}

Then you must set sectionForKeyPath in the NSFetchedResultsController initializer to be the transient attribute key in the data model and the cache name if desired.

override func viewDidLoad() {
        super.viewDidLoad()

        fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: managedObjectContext!, sectionNameKeyPath: "section", cacheName: "Root")
        fetchedResultsController?.delegate = self
        fetchedResultsController?.performFetch(nil)

        tableView.reloadData()
}

func fetchRequest() -> NSFetchRequest {

    var fetchRequest = NSFetchRequest(entityName: "Number")
    let sortDescriptor = NSSortDescriptor(key: "number", ascending: false)

    fetchRequest.predicate = nil
    fetchRequest.sortDescriptors = [sortDescriptor]
    fetchRequest.fetchBatchSize = 20

    return fetchRequest
}

The result is a UITableViewController with grades sorted by pass or fail dynamically:

I made a sample project that can be found on GitHub.



回答2:

"Transient" and "computed" in the sense you mean are different things and are mutually exclusive.

Transient means that the value is stored in memory on the object graph. Computed means that the value is stored nowhere and is calculated in the getter. Both are distinct from the classic non-transient attribute which is stored on the object graph and is saved to disk.

@NSManaged can only be applied to attributes that have a slot in your managed object model.



回答3:

Remove the NSManaged attribute.