Reputation: 43068
I have the following protocol
protocol JSONInitializable {
static func initialize(fromJSON: NSDictionary) throws -> Self?
}
Now I'm trying to make that function return whatever class has conformed to the protocol. I.e. if I have class Foo
conforming to the protocol, I want to return a Foo
object from the method. How can I do this?
extension Foo: JSONInitializable {
static func initialize(fromJSON: NSDictionary) throws -> Foo? {
}
}
I get the error:
Method 'initialize' in non-final class 'Foo' must return 'Self' to conform to protocol 'JSONInitializable'
Upvotes: 4
Views: 1952
Reputation: 62052
Autocomplete will help you, but basically, if Foo
is a class, you just need a method which matches the exact signature of the method in your protocol:
class Foo {}
protocol JSONInitializable {
static func initialize(fromJSON: [String : AnyObject]) throws -> Self?
}
extension Foo: JSONInitializable {
static func initialize(fromJSON: [String : AnyObject]) throws -> Self? {
return nil
}
}
As a note here, you will have to, within this method, replace all instances of Foo
with Self
. If you want to use a constructor, it will have to be one marked as required.
With this in mind, it probably makes more sense to change your protocol to requiring an initializer rather than a static method called initialize
, in which case, take a look at Blake Lockley's answer. However, this answer stands to answer the question of how to deal with Self
in protocols, as there are certainly cases where we might want a method that returns Self
that isn't an initializer.
If Foo
is not a class, it is a value type which cannot be subclasses, and as such, we return the name of the type:
struct Foo: JSONInitializable {
static func initialize(fromJSON: [String : AnyObject]) throws -> Foo? {
return nil
}
}
enum Foo: JSONInitializable {
case One, Two, Three
static func initialize(fromJSON: [String : AnyObject]) throws -> Foo? {
return nil
}
}
The reason you need to return Self?
from the method in the case of a class is because of inheritance. The protocol declares that if you conform to it, you will have a method called initialize
whose return type will be an optional version of whatever you are.
If we write Foo
's initialize
method as you wrote it, then if we subclass Foo
with Bar
, then now we have broken our conformance to the protocol. Bar
has inherited the conformance to the protocol from Foo
, but it doesn't have a method which is called initialize
and returns Bar?
. It has one that returns Foo
.
Using Self
here means that when our subclasses inherit this method, it will return whatever type they are. Self
is Swift's equivalent of Objective-C's instancetype
.
Upvotes: 3
Reputation: 2961
As mentioned in nhgrif answer change the return type of Foo?
to self?
.
Alternatively
In Swift you can declare init
s in protocol so try something like this:
protocol JSONInitializable {
init?(fromJSON: NSDictionary) throws
}
extension Foo: JSONInitializable {
required init?(fromJSON: NSDictionary) throws {
//Possibly throws or returns nil
}
}
Upvotes: 1