Reputation: 11
I am trying to implement a protocol extension JsonProcess which has a function that takes NSData as the argument and i want to create different protocol extensions using self requirement something like this
extension JSONResource where Self: Login {
func proccessJSON(data: NSData) -> Self{
return Login()
}
}
but the compiler shows an error
Cannot convert return expression of type 'Login' to return type 'Self'
the Login class is defined like this
class Login: NSObject {
var username: String?
var firstName: String?
}
what should I return here if i serialize the NSData and create an isntanse of the Login class populate it and try to return it?
Upvotes: 1
Views: 651
Reputation: 80781
The problem here is that Self
is potentially more type-specific than Login
. Let's say you create a subclass of Login
:
class TopSecretLogin : Login {
var topSecret : String?
}
Now when you come to use your protocol extension on an instance of TopSecretLogin
(assuming Login
conforms to JSONResource
in the first place) – your processJSON
method says that it returns Self
, which is TopSecretLogin
in this case. However, you're trying to return a Login
. Therefore the compiler isn't happy, as you cannot pass a superclass to something that expects its subclass.
The solution depends on whether you intend for Login
to be subclassed. If you don't intend for it to be subclassed, then simply change the method signature to returning a Login
, and make Login
a final class
.
If you do intend for this, you need to add a required initialiser to Login
, allowing you to construct an arbitrary instance of Self
in your protocol extension. An example setup could look like this:
protocol JSONResource {}
class Login : NSObject, JSONResource {
var username: String?
var firstName: String?
required override init() {
super.init()
}
}
class TopSecretLogin : Login {
var topSecret : String?
required init() {
super.init()
}
}
extension JSONResource where Self : Login {
func processJSON(data: NSData) -> Self {
// do some processing...
return Self()
}
}
let someData = // ...
let l = Login()
l.processJSON(someData) // returns Login
let t = TopSecretLogin()
t.processJSON(someData) // returns TopSecretLogin
Although that all being said, wouldn't it make more sense if processJSON
was a static method instead of an instance method? To me it doesn't look like it needs to operate on an instance, it just creates a new instance from a given set of NSData
.
You also may want to consider making processJSON
a protocol requirement, as surely anything that's a JSONResource
should be able to processJSON
? In that case you'll want to extend Login
rather than the protocol itself in order to implement the method. You can then create a new instance through self.init()
at the static scope, or self.dynamicType.init()
at instance scope.
You may also want to consider doing this with an initialiser:
protocol JSONResource {
init(jsonData:NSData)
}
class Login : NSObject, JSONResource {
var username: String?
var firstName: String?
required init(jsonData:NSData) {
// do some processing
super.init()
}
}
class TopSecretLogin : Login {
var topSecret : String?
required init(jsonData:NSData) {
// do some processing
super.init(jsonData:jsonData)
}
}
let someData = // ...
let l = Login(jsonData: someData) // returns Login
let t = TopSecretLogin(jsonData: someData) // returns TopSecretLogin
Upvotes: 1
Reputation: 4533
Since you specified that the extension only applies if conforming object Self
is class Login
you should write extension like this:
extension JSONResource where Self: Login {
func proccessJSON(data: NSData) -> Login {
return Login()
}
}
Upvotes: 1