Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift protocol defining class method returning self

I had code that was working in XCode 6 beta but stopped working recently after updating to xcode 6.1.

This is my protocol:

protocol CanDeserialiseFromJson {
    class func FromJson(json : JSONValue) -> Self
}

This is implementation:

extension Invoice : CanDeserialiseFromJson {
    class func FromJson(json : JSONValue) -> Self {
        return Invoice()
    }
}

This fails giving error:

'Invoice' is not convertable to 'Self'

As I said, this used to work and I can't work out why it doesn't anymore

like image 504
Stanislaw Wozniak Avatar asked Oct 07 '14 20:10

Stanislaw Wozniak


3 Answers

It's right. Your method is declared to return Self, whereas you are returning Invoice. Class methods are inherited, and in subclasses, Self will be that subclass type, and Invoice is not a subtype of that type.

To actually return Self, assuming Invoice has a required init() constructor, you can do something like this:

extension Invoice : CanDeserialiseFromJson {
    class func FromJson(json : JSONValue) -> Self {
        return self()
    }
}
like image 51
newacct Avatar answered Nov 14 '22 00:11

newacct


Self in a protocol is a requirement that implementations of the protocol use their own type. Since Invoice is the type you're adopting the protocol in, your implementation of FromJson should have a return type of Invoice.

like image 36
rickster Avatar answered Nov 14 '22 00:11

rickster


In case you really need to return Self (in my case I have an Objective-C protocol that translates a method into swift function returning Self) and not mark your class as final, you need to create a required initializer and use that:

class Foo {
    static func bar() -> Self {
        return self.init()
    }

    required init() {

    }
}

The final/required requirement comes from the fact that you might subclass this class and have a different initialiser. Final removes the option for a subclass, while the required init makes sure that any subclass will implement the required initialiser used in the static method.

like image 1
Морт Avatar answered Nov 14 '22 01:11

Морт