Swift, Self from AnyObject
Can I get Self from AnyObject?
Let's take this example:
// Superclass
class ManagedObject {
class func findByID(id: String) -> AnyObject? {
let objects = objectsWithPredicate(NSPredicate(format: "id == %@", id))
return objects.firstObject() // Returns AnyObject
}
}
// Subclass
class User : ManagedObject {
class func returnFirstSelf() -> Self? {
return findById("1") // This doesn't work because it returns AnyObject, but I need Self.
}
}
If not, the best alternative way is to make sure that when called, the User.returnFirstSelf()
compiler returns User
, and when called, UserSubclass.returnFirstSelf()
it returns UserSubclass
.
source to share
You can simply return User?
from your class function if it's an option:
public class func returnFirstSelf() -> User? {
if let found = findByID("1") as? User {
return found
}
return nil
}
There is currently no (I know) return Self?
using Swift as it stands. The problem is that it Self
has several ... "dynamic" meaning, separate from specific types, protocols, and even generics. A concrete example to demonstrate this: What if you have a class StudentUser
that extends User
? If you tried to implement it like this:
class func returnFirstSelf() -> Self? {
if let found = findById("1") as? Self { // Note the check that 'found' is a 'Self'
return found
}
return nil
}
Then you run into a compiler error because you cannot use Self
outside the result of a protocol or class method. And if you try to implement it like this:
class func returnFirstSelf() -> Self? {
if let found = findById("1") as? User { // Note 'User' instead of 'Self'
return found
}
return nil
}
Then you run the risk of Self
actually mean StudentUser
, and even if you hand over a check that requires found
how User
, it does not guarantee that it found
will be StudentUser
. This will happen in case it StudentUser
does not override the method to ensure that it as?
checks StudentUser
.
The critical flaw here , in my opinion, is that you cannot use a keyword required
for class methods, requiring subclasses to override them. This will allow the compiler to ensure that any subclasses override this method and provide an implementation that can guarantee type safety.
source to share
Craig Otis's answer is in place. However, one option is to create a copy constructor. This may not work for a polling scenario where they inherit from an NSManagedObject, but it should work for non-managed objects.
required init(user: User) {
super.init(user: User) // or super.init() if top of inheritance.
self.name = user.name
self.email = user.email
// etc.
}
class func returnFirstSelf() -> Self? {
if let found = findById("1") { // Note the check that 'found' is a 'Self'
return self.init(copy: found as! User)
}
return nil
}
source to share