强制类型转换不适用于通用函数范围。为什么?

时间:2018-07-04 08:30:14

标签: ios swift xcode generics casting

我在项目中做了一个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范围内的类型?

1 个答案:

答案 0 :(得分:0)

在您的第一段代码中,您将HomeViewController.self作为viewClass进行传递,因此它知道buildViewFinal将返回HomeViewController的实例和{{ 1}}具有HomeViewController属性。

在第二个代码段中,编译器对presenter一无所知,因此不能假定其将具有T属性。

您可以使用类型约束来强制presenterT或任何定义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,所以您最好还是使用良好的旧继承