Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I return instancetype in Swift [duplicate]

I want to make an extension of some class to return the runtime type object

for example, I create extenstion of class A

extension A {
    class func niceObject() -> XXXXX { // in objective-c is instancetype
        return ....
    }
}

So anyone know there is instancetype keyword in Swift or not to replace xxxxx and I can call this function on subclass of A without manually cast

var b: B = B.niceObject()

Thanks

like image 750
Zoon Nooz Avatar asked Jun 12 '14 09:06

Zoon Nooz


3 Answers

You can do it. Playground code below. It's self() that niceObject() has to return. Additionally, you must have a required init on the base class.

class A {
    required init() {
    }

    func whatClassAmI() -> String {
        return "Class A"
    }
}

class B: A {
    required init() {
        super.init()
    } 
    override func whatClassAmI() -> String {
        return "Class B"
    }
}

let a = A()
let sa = a.whatClassAmI() // "Class A", of course

let b = B()
let sb = b.whatClassAmI() // "Class B", of course

extension A {
    class func niceObject() -> Self {
        return self.init()
    }
}

let aa = A.niceObject()
let saa = aa.whatClassAmI() // "Class A"

let bb = B.niceObject()
let sbb = bb.whatClassAmI() // "Class B", as required
like image 113
Grimxn Avatar answered Sep 29 '22 09:09

Grimxn


There is a keyword Self which is allowed in two places - in protocols (see Jean-Philippe Pellet's answer) and as a result of class methods:

extension A {
    class func niceObject() -> Self? {
        return nil
    }
}

Unfortunately, this won't help you because the following is invalid

extension A {
     class func niceObject() -> Self? {
         //A can't be converted to Self
         return A()
     }
 }

The error is caused by the fact that when you inherit from A

class B : A {
}

then

var b = B.niceObject()

would actually return an A instance which is not convertible to Self (Self is B)

@Grimxn found the correct solution (See his answer):

You have to add a required initializer to the base class, e.g.

class A {
   @required init() {
   } 
}

and then you can call the initialiser using self()

extension A {
     class func niceObject() -> Self {
         return self()
     }
 }
like image 22
Sulthan Avatar answered Sep 29 '22 08:09

Sulthan


At least in procotols, you can use Self. This represents the actual type of self. Not sure about extensions, though...

For instance, see the definition of Equatable:

protocol Equatable {
    func ==(lhs: Self, rhs: Self) -> Bool
}
like image 10
Jean-Philippe Pellet Avatar answered Sep 29 '22 08:09

Jean-Philippe Pellet