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!
}
}
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.
"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.
Remove the NSManaged
attribute.