Swift通用类型

时间:2018-12-16 04:32:45

标签: ios swift generics swift4

嗨,我是迅速编写iOS应用程序的新手。 我想知道如何更好地使用泛型传递结果数据。

我有一个委托人,负责提供服务器中的人的数据

protocol PersonDataProvider {
    func dataReceived(_ result: PersonResult)
}

结果可以通过枚举获得成功和失败状态。

enum PersonResult {
    case success
    case networkFailed
}

下面的类调用服务器api并获取数据,然后传回

class MyNetworkClass {

    var personDataProvider: PersonDataProvider
    func getDataFromServer() {
        personDataProvider.dataReceived(.success)
    }
}

下面是我订阅提供程序的Viewcontroller

class MyViewController: PersonDataProvider {

    func dataReceived(_ result: PersonResult) {

        switch result {
        case .success:
            print("success")

        case .networkFailed:
            print("no network")

        }
    }

}

现在,我想发送带有成功块的额外信息,该信息可以是下面的数据模型。它可以是任何类型。

class Employer:Person {
    let id
    let salary
}

class Student:Person {
    let id
    let rollNumber
}

我该如何实现?我可以在协议中定义关联类型并实现吗?

我如何订阅“ PersonDataProvider”的“ MyViewController”可以定义他期望的“成功”块的结果类型?

2 个答案:

答案 0 :(得分:1)

将关联值用作.success案例的一部分。

比方说,对于您这类的人,您有一个超类人。然后像这样定义您的枚举:

enum PersonResult {
    case success(Person)
    case networkFailed
}

现在,当您交出.success值时,必须提供一个Person来配合它:

func getDataFromServer() {
    let person = Student.init(...) // initialize, or fetch, or whatever
    personDataProvider.dataReceived(.success(person))
}

这里是一个完整的伪造示例,它模拟了整个过程;您必须更改详细信息,但要注意的是,它将编译:

enum PersonResult {
    case success(Person)
    case networkFailed
}
protocol PersonDataProvider {
    func dataReceived(_ result: PersonResult)
}
class MyNetworkClass {
    var personDataProvider: PersonDataProvider!
    func getDataFromServer() {
        let person = Student.init(id: 3, rollNumber: 10)
        personDataProvider.dataReceived(.success(person))
    }
}
class Person {}
class Employer:Person {
    let id : Int
    let salary : Int
    init(id:Int, salary:Int) {
        self.id = id; self.salary = salary
    }
}
class Student:Person {
    let id : Int
    let rollNumber : Int
    init(id:Int, rollNumber:Int) {
        self.id = id; self.rollNumber = rollNumber
    }
}

答案 1 :(得分:0)

您必须摆脱委派模式才能实现所需的功能。取而代之的是,您将需要 Result 类型的通用enum和您的数据模型类型通用的网络class

enum Result<T> {
    case success(T)
    case networkFailed
}

class MyNetworkClass<T: Person> {
    func getDataFromServer(completion: @escaping (Result<T>)-> Void) {
        // here goes your implementation (data fetching)
        // for demonstration purpose I just initialized object
        if let student = Student(id: 112233, rollNumber: 25) as? T {
            completion(Result.success(student))
        } else if let employer = Employer(id: 445566, salary: 5200) as? T {
            completion(Result.success(employer))
        } else {
            completion(Result.networkFailed)
        }
    }
}

那么您的用法将是:

MyNetworkClass().getDataFromServer { (result: Result<Student>) in // you can also use Employer type
    switch result {
    case .success(let student):
        print(student.id)
    case .networkFailed:
        print("Error")
    }
}