1

我正在尝试实现一个协议扩展 JsonProcess,它有一个以 NSData 作为参数的函数,我想使用类似这样的自我要求创建不同的协议扩展

extension JSONResource where Self: Login {
    func proccessJSON(data: NSData) -> Self{
        return Login()
    }
}

但编译器显示错误

无法将“登录”类型的返回表达式转换为“自我”类型的返回表达式

Login 类是这样定义的

class Login: NSObject {
    var username: String?
    var firstName: String?
}

如果我序列化 NSData 并创建 Login 类的实例填充它并尝试返回它,我应该在这里返回什么?

4

2 回答 2

1

由于您指定扩展仅适用于符合对象Self是类的Login情况,因此您应该像这样编写扩展:

extension JSONResource where Self: Login {
    func proccessJSON(data: NSData) -> Login {
        return Login()
    }
}
于 2016-06-06T12:30:32.730 回答
1

这里的问题是它Self可能比Login. 假设您创建了一个子类Login

class TopSecretLogin : Login {
    var topSecret : String?
}

TopSecretLogin现在,当您在(假设首先Login符合)的实例上使用您的协议扩展时JSONResource- 您的processJSON方法说它返回SelfTopSecretLogin在这种情况下就是这样。但是,您正在尝试返回一个Login. 因此编译器不高兴,因为您不能将超类传递给期望其子类的东西。

解决方案取决于您是否打算Login被子类化。如果您不打算将其子类化,则只需将方法签名更改为返回 a Login,然后制作Logina final class

如果您确实打算这样做,则需要将所需的初始化程序添加到,允许您在协议扩展中Login构造任意实例。Self示例设置可能如下所示:

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

processJSON虽然说了这么多,但如果是静态方法而不是实例方法不是更有意义吗?对我来说,它看起来不需要对实例进行操作,它只是从给定的一组NSData.

您可能还想考虑制定processJSON协议要求,就像任何JSONResource应该能够做到的那样processJSON?在这种情况下,您需要扩展Login而不是协议本身来实现该方法。self.init()然后,您可以在静态范围或self.dynamicType.init()实例范围内创建新实例。

您可能还需要考虑使用初始化程序执行此操作:

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
于 2016-06-06T13:00:00.323 回答