我正在尝试编写一个函数,该函数1(实例化UIViewController的子类,2(推送到调用方UIViewController的导航控制器。
到目前为止,我有这个:
func pushAnyViewController<T>(viewController:T, storyboardName:String) {
// Instantiate the view controller of type T
guard let nextViewController = UIStoryboard(name: storyboardName, bundle: nil).instantiateViewController(withIdentifier: String(describing: T.self)) as? T else {
return
}
viewController.navigationController.pushViewController(nextViewController, animated: true)
}
这会产生错误
类型为"T"的值没有成员"导航控制器">
我不确定我是否应该以某种方式说T将永远是UIViewController的子类。如果是这样的话,不清楚我在哪里这样做。为此,我想到了:
func pushAnyViewController<T>(viewController:T & UIViewController, storyboardName:String)
但这会产生错误:
函数签名中不使用泛型参数"T">
非协议、非类类型"T"不能在协议约束类型中使用
您需要确定T
是具有<T:UIViewController>
的 vc
func pushAnyViewController<T:UIViewController>(viewController:T, storyboardName:String) {
guard let nextViewController = UIStoryboard(name: storyboardName, bundle: nil).instantiateViewController(withIdentifier: String(describing: T.self)) as? T else { return }
viewController.navigationController?.pushViewController(nextViewController, animated: true)
}
最高答案不适合我,我需要一个更通用的解决方案。首先,我需要传递数据的选项,其次,我希望有一个可以推送或呈现VC的泛型函数,最后,我希望我的泛型函数可以从任何地方调用,而不仅仅是从UIViewController调用,这就是为什么UIViewController的扩展不适合我。
我决定使用简单的 init 和两个公共方法创建一个结构,以便我可以在任何地方创建副本并调用这些方法。
struct Navigator {
// MARK: - DisplayVCType enum
enum DisplayVCType {
case push
case present
}
// MARK: - Properties
private var viewController: UIViewController
static private let mainSBName = "Main"
// MARK: - Init
init(vc: UIViewController) {
self.viewController = vc
}
// MARK: - Public Methods
public func instantiateVC<T>(withDestinationViewControllerType vcType: T.Type,
andStoryboardName sbName: String = mainSBName) -> T? where T: UIViewController {
let storyBoard: UIStoryboard = UIStoryboard(name: sbName, bundle: nil)
let destinationVC = storyBoard.instantiateViewController(withIdentifier: String(describing: vcType.self))
return destinationVC as? T
}
public func goTo(viewController destinationVC: UIViewController,
withDisplayVCType type: DisplayVCType = .present,
andModalPresentationStyle style: UIModalPresentationStyle = .popover) {
switch type {
case .push:
viewController.navigationController?.pushViewController(destinationVC, animated: true)
case .present:
destinationVC.modalPresentationStyle = style
viewController.present(destinationVC, animated: true, completion: nil)
}
}
}
以及一些 VC 中的示例调用,在推送后传递字符串:
class SomeVC: UIViewController {
var navigator: Navigator?
override func viewDidLoad() {
super.viewDidLoad()
navigator = Navigator(vc: self)
}
func pushVC() {
guard let vc = navigator?.instantiateVC(withDestinationViewControllerType: VC1.self) else { return }
vc.someString = "SOME STRING TO BE PASSED"
navigator?.goTo(viewController: vc, withDisplayVCType: .push)
}
func presentVC() {
guard let vc = navigator?.instantiateVC(withDestinationViewControllerType: TableViewController.self) else { return }
navigator?.goTo(viewController: vc, withDisplayVCType: .present)
}
}
借助一些关键字。
enum Storyboard : String {
case Main
}
func viewController(_ viewController: UIViewController.Type) -> some UIViewController {
return UIStoryboard(name: self.rawValue, bundle: nil).instantiateViewController(withIdentifier: String(describing: viewController.self))
}