Типы Swift Generic - PullRequest
       11

Типы Swift Generic

0 голосов
/ 16 декабря 2018

Привет, я новичок в разработке и написании приложений для 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
}

Как мне этого добиться?Могу ли я определить ассоциированный тип в протоколе и добиться, если да, то как?

Как подписчик "MyViewController" из "PersonDataProvider" может определить тип результата, который он ожидает от блока "success"?

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Вы должны отойти от шаблона делегирования, чтобы достичь чего-то вроде того, что вы хотите.Вместо этого вам понадобится общий enum из Result type и ваша сеть 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")
    }
}
0 голосов
/ 16 декабря 2018

Используйте ассоциированное значение как часть дела .success.

Допустим, у вас есть человек суперкласса для ваших типов людей.Затем определите ваше перечисление следующим образом:

enum PersonResult {
    case success(Person)
    case networkFailed
}

Теперь, когда вы возвращаете значение .success, вы должны указать человека, который будет его использовать:

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
    }
}
...