Swift protocol defining class method returning sel

2020-07-11 06:32发布

问题:

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

回答1:

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.



回答2:

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()
    }
}


回答3:

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.