This pitch is the result of a question "Dynamic member lookup on specific typed properties".
The swift compiler should tranlate this
class Token {
dynamic var expiresAfter : Double?
...
}
into this
class Token {
var expiresAfter : Double? {
get { return self[dynamicMember: #function] }
set { self[dynamicMember: #function] = newValue }
}
...
}
The current alternatives are:
- write this boilerplate code for each and every property
- define the properties in a seperate file, then generate the boilerplate code
- use
@dynamicMemberLookup
The final alternative is actually the worst because it throws the door open to code such as:
@dynamicMemberLookup
class Token {
...
}
var token = Token()
token.expiresAfter = "Hello World"
Note that we know about expiresAfter
at compile time but we're not allowed to tell the compiler about the type even if we know it.
@NSManaged
Trevor Squires's article Why Swift is the most satisfying language for using Core Data showed how to use Core Data in Swift for a more satisfying experience
However the best he could come up with given Swift was this:
class Token : NSManagedObject {
var expiresAfter: Double? {
get {
let member = #function
willAccessValue(forKey: member)
defer { didAccessValue(forKey: member) }
let number = primitiveValue(forKey: member) as? NSNumber
return number?.doubleValue
}
set {
let member = #function
willChangeValue(forKey: member)
defer { didChangeValue(forKey: member) }
let number = newValue.map({NSNumber(value: $0)})
setPrimitiveValue(number, forKey: member)
}
}
}
(Note that I've modified Trevor's example to replace @NSManaged
with the functionally equivalent primitiveValue(forKey:)
{%.language=swift})
With Swift only dynamic
one could write this instead:
class Token: ManagedObject {
dynamic var expiresAfter: Double?
}
with the subscript(dynamicMember:)
being moved to a base class
class ManagedObject : NSManagedObject {
subscript(dynamicMember member: String) -> Double? {
get {
willAccessValue(forKey: member)
defer { didAccessValue(forKey: member) }
let number = primitiveValue(forKey: member) as? NSNumber
return number?.doubleValue
}
set(newValue) {
willChangeValue(forKey: member)
defer { didChangeValue(forKey: member) }
let number = newValue.map({NSNumber(value: $0)})
setPrimitiveValue(number, forKey: member)
}
}
}