Тип приведения не работает в области общих функций. Зачем? - PullRequest
0 голосов
/ 04 июля 2018

Я сделал класс Router (подкласс UINavigationController) в моем проекте для централизации и минимизации кода, используемого для создания экземпляров и навигации между представлениями. Но когда я пытаюсь свернуть конкретную функцию (buildView), приведение типов не работает. Но это прекрасно работает вне области функции buildView, то же самое без оператора as! в функции goHome.

enum Routes {
    case home
    case account

    var file: String {

        switch self {
        case .home:
            return "HomeView"
        case .account:
            return "AccountView"
    }
}

protocol HomeInterface: class {

    func goTo(view: Routes)
    func showModal(view: Routes, caller: UIViewController)
}

class HomePresenter: NSObject, HomeInterface {
    init(view: HomeViewInterface) {

        self.view = view
    }
    internal func goTo(view: Routes) { /* Implementation */ }
    internal func showModal(view: Routes, caller: UIViewController) {/* Implementation */ }
}


protocol HomeViewInterface: class { 
/* Implementation */
}

class HomeViewController: UIViewController, HomeViewInterface {

        var presenter: HomeInterface?

        override func viewDidLoad() {
            super.viewDidLoad()
        }
    /* Implementation */
}

Рабочий код

    func goHome() {

        let viewInstance = buildView(view.file, HomeViewController.identifier, HomeViewController.self)

        viewInstance.presenter = HomePresenter(view: viewInstance)
        self.view?.pushViewController(viewInstance, animated: true)
    }

    private func buildView<T>(_ nameFile: String, _ identifier: String, _ viewClass: T.Type) -> T {

        return UIStoryboard(name: nameFile, bundle: nil).instantiateViewController(withIdentifier: identifier) as! T
    }

Желаемый финальный код, но не работает:

func goHome() { 
    buildViewFinal(view.file, HomeViewController.identifier, HomeViewController.self)
}

func buildViewFinal<T, P>(_ nameFile: String, _ identifier: String, viewClass: T, presenter: P) {

    let viewInstance = UIStoryboard(name: nameFile, bundle: nil).instantiateViewController(withIdentifier: identifier) as? T

    viewInstance.presenter = P(view: viewInstance)
    self.view?.pushViewController(viewInstance, animated: true)
}

Когда я пытаюсь свести код только к функции buildViewFinal, свойство presenter из viewInstance не распознается, показывая ошибку компиляции

Значение типа 'T?' не имеет члена 'ведущий'

, а в pushViewController показать ошибку:

Не удалось преобразовать значение типа 'T?' к ожидаемому типу элемента 'UIViewController'

Основная цель - превратить весь код в полезную и простую навигацию.

Итак, как это хорошо работает в первом коде, но не удается распознать тип внутри buildViewFinal scope?

1 Ответ

0 голосов
/ 04 июля 2018

В вашем первом фрагменте кода вы передаете HomeViewController.self как viewClass, и поэтому он знает, что buildViewFinal собирается вернуть экземпляр HomeViewController и что HomeViewController имеет свойство presenter.

Во втором фрагменте кода компилятор ничего не знает о T, поэтому он не может предполагать, что у него будет свойство presenter.

Вы можете использовать ограничение типа, чтобы принудительно установить, что T является HomeViewController или любым другим классом, определяющим свойство presenter:

func buildViewFinal<T: HomeInterface, P>(_ nameFile: String, _ identifier: String, viewClass: T, presenter: P) {

    let viewInstance = UIStoryboard(name: nameFile, bundle: nil).instantiateViewController(withIdentifier: identifier) as? T

    viewInstance.presenter = P(view: viewInstance)
    self.view?.pushViewController(viewInstance, animated: true)
}

но тогда у вас возникнет проблема, что viewInstance не может быть выдвинут, потому что компилятор не знает, что это экземпляр подкласса UIViewController.

Действительно, дженерики и протоколы просто усложняют ситуацию.

Вы имеете дело с UIKit, который ориентирован на класс, так что вы можете просто использовать старое доброе наследование

...