我在项目中做了一个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
范围内的类型?
答案 0 :(得分:0)
在您的第一段代码中,您将HomeViewController.self
作为viewClass
进行传递,因此它知道buildViewFinal
将返回HomeViewController
的实例和{{ 1}}具有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,所以您最好还是使用良好的旧继承