AppCoordinator 通过视图控制器委托
AppCoordinator delegate through view controllers
我正在尝试了解协调器模式是如何工作的,尽管我遇到了从一个子协调器的视图控制器到另一个子协调器的委托的一些问题。
例如,我有一个家 vc,我想通过一个按钮转到详细信息,但我希望使用以下代码从 HomeTabBarCoordinator 对其进行管理。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow()
let tabBarController = UITabBarController()
window?.rootViewController = tabBarController
let about = HomeTabBarCoordinator()
let one = deGenericize(about)
let appCoordinator = TabAppCoordinator(tabBarController: tabBarController, tabs: [one])
appCoordinator.start()
window?.makeKeyAndVisible()
return true
}
public protocol TabCoordinator {
associatedtype RootType: UIViewController
var rootController: RootType { get }
var tabBarItem: UITabBarItem { get }
}
public class AnyTabCoordinator {
var rootController: UIViewController
var tabBarItem: UITabBarItem
public init<T: TabCoordinator>(_ tabCoordinator: T) {
rootController = tabCoordinator.rootController
tabBarItem = tabCoordinator.tabBarItem
}
}
public func deGenericize<T: TabCoordinator>(_ coordinator: T) -> AnyTabCoordinator {
return AnyTabCoordinator(coordinator)
}
public class TabAppCoordinator {
var tabBarController: UITabBarController
var tabs: [AnyTabCoordinator]
public init(tabBarController: UITabBarController, tabs: [AnyTabCoordinator]) {
self.tabBarController = tabBarController
self.tabs = tabs
}
public func start() {
tabBarController.viewControllers = tabs.map { (coordinator) -> UIViewController in
return coordinator.rootController
}
}
}
protocol HomeTabBarDelegate: class {
func goToProfile()
}
class HomeTabBarCoordinator: NSObject, TabCoordinator {
var rootController: UINavigationController
var tabBarItem: UITabBarItem = UITabBarItem(title: "About", image: UIImage(named: "AboutTabBarIcon"), selectedImage: UIImage(named: "AboutTabBarIcon_Filled"))
let homeVC: HomeViewController
override init() {
self.homeVC = HomeViewController()
self.rootController = UINavigationController()
super.init()
rootController.viewControllers = [homeVC]
rootController.tabBarItem = tabBarItem
homeVC.delegate = self //is being set properly when i add a breakpoint here
}
}
extension HomeTabBarCoordinator: HomeTabBarDelegate {
func goToProfile() { //never being executed
let details = DetailsViewController()
rootController.pushViewController(details, animated: true)
}
}
class HomeViewController: UIViewController {
weak var delegate: HomeTabBarDelegate?
let button = UIButton()
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView() {
view.addSubview(button)
button.snp.makeConstraints { (make) in
make.center.equalToSuperview()
}
view.backgroundColor = .white
button.setTitle("test", for: .normal)
button.setTitleColor(.red, for: .normal)
button.addTarget(self, action: #selector(didPress), for: .touchDown)
}
@objc func didPress() {
delegate?.goToProfile() //delegate is nil
}
override func viewDidLoad() {
super.viewDidLoad()
setupView()
// Do any additional setup after loading the view.
}
}
我不知道发生了什么,它一直在 HomeViewController 中给我一个 nil 委托(请参阅代码中的注释)。
有什么想法吗?
更新
正如@purpose 提到的 HomeTabBarCoordinator
从 didFinishLaunchingWithOptions
中解除分配,我将 appDelegate 函数更改为以下内容,但仍然存在相同的问题。我怎样才能保持强大的参考。至 let about = HomeTabBarCoordinator()
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var appCoordinator: TabAppCoordinator?
let tabBarController = UITabBarController()
let about = HomeTabBarCoordinator()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let one = deGenericize(about)
appCoordinator = TabAppCoordinator(tabBarController: tabBarController, tabs: [one])
appCoordinator?.start()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
违规代码:
let about = HomeTabBarCoordinator()
它有什么作用?它创建一个局部变量并在其中存储一个 HomeTabBarCooordinator()
对象。
一旦 application(_:didFinishLaunchingWithOptions)
消失,它会做什么?它当然会取消初始化,因为没有创建新的强引用(声明委托是件好事!)。
你可能认为
public init<T: TabCoordinator>(_ tabCoordinator: T) {
rootController = tabCoordinator.rootController
tabBarItem = tabCoordinator.tabBarItem
}
会救你的。让我们看看 rootController
或 tabBarItem
是否强烈引用我们的 HomeTabBarCoordinator
:
class HomeTabBarCoordinator: NSObject, TabCoordinator {
var rootController: UINavigationController
var tabBarItem: UITabBarItem = UITabBarItem(title: "About", image: UIImage(named: "AboutTabBarIcon"), selectedImage: UIImage(named: "AboutTabBarIcon_Filled"))
let homeVC: HomeViewController
override init() {
self.homeVC = HomeViewController()
self.rootController = UINavigationController()
super.init()
rootController.viewControllers = [homeVC]
rootController.tabBarItem = tabBarItem
homeVC.delegate = self //is being set properly when i add a breakpoint here
}
}
不,他们没有。再见HomeTabBarCoordinator
!所以 delegate
变为零。
How can i keep a strong ref. to let about = HomeTabBarCoordinator()
把它放在一个本身被强引用的class中就足够了。任何未声明 [=37=] 的引用都是强大的,并且在封装 class 存在的情况下将存在。
而且 AppDelegate
可以肯定的是它不会自行取消初始化。
我正在尝试了解协调器模式是如何工作的,尽管我遇到了从一个子协调器的视图控制器到另一个子协调器的委托的一些问题。 例如,我有一个家 vc,我想通过一个按钮转到详细信息,但我希望使用以下代码从 HomeTabBarCoordinator 对其进行管理。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow()
let tabBarController = UITabBarController()
window?.rootViewController = tabBarController
let about = HomeTabBarCoordinator()
let one = deGenericize(about)
let appCoordinator = TabAppCoordinator(tabBarController: tabBarController, tabs: [one])
appCoordinator.start()
window?.makeKeyAndVisible()
return true
}
public protocol TabCoordinator {
associatedtype RootType: UIViewController
var rootController: RootType { get }
var tabBarItem: UITabBarItem { get }
}
public class AnyTabCoordinator {
var rootController: UIViewController
var tabBarItem: UITabBarItem
public init<T: TabCoordinator>(_ tabCoordinator: T) {
rootController = tabCoordinator.rootController
tabBarItem = tabCoordinator.tabBarItem
}
}
public func deGenericize<T: TabCoordinator>(_ coordinator: T) -> AnyTabCoordinator {
return AnyTabCoordinator(coordinator)
}
public class TabAppCoordinator {
var tabBarController: UITabBarController
var tabs: [AnyTabCoordinator]
public init(tabBarController: UITabBarController, tabs: [AnyTabCoordinator]) {
self.tabBarController = tabBarController
self.tabs = tabs
}
public func start() {
tabBarController.viewControllers = tabs.map { (coordinator) -> UIViewController in
return coordinator.rootController
}
}
}
protocol HomeTabBarDelegate: class {
func goToProfile()
}
class HomeTabBarCoordinator: NSObject, TabCoordinator {
var rootController: UINavigationController
var tabBarItem: UITabBarItem = UITabBarItem(title: "About", image: UIImage(named: "AboutTabBarIcon"), selectedImage: UIImage(named: "AboutTabBarIcon_Filled"))
let homeVC: HomeViewController
override init() {
self.homeVC = HomeViewController()
self.rootController = UINavigationController()
super.init()
rootController.viewControllers = [homeVC]
rootController.tabBarItem = tabBarItem
homeVC.delegate = self //is being set properly when i add a breakpoint here
}
}
extension HomeTabBarCoordinator: HomeTabBarDelegate {
func goToProfile() { //never being executed
let details = DetailsViewController()
rootController.pushViewController(details, animated: true)
}
}
class HomeViewController: UIViewController {
weak var delegate: HomeTabBarDelegate?
let button = UIButton()
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView() {
view.addSubview(button)
button.snp.makeConstraints { (make) in
make.center.equalToSuperview()
}
view.backgroundColor = .white
button.setTitle("test", for: .normal)
button.setTitleColor(.red, for: .normal)
button.addTarget(self, action: #selector(didPress), for: .touchDown)
}
@objc func didPress() {
delegate?.goToProfile() //delegate is nil
}
override func viewDidLoad() {
super.viewDidLoad()
setupView()
// Do any additional setup after loading the view.
}
}
我不知道发生了什么,它一直在 HomeViewController 中给我一个 nil 委托(请参阅代码中的注释)。 有什么想法吗?
更新
正如@purpose 提到的 HomeTabBarCoordinator
从 didFinishLaunchingWithOptions
中解除分配,我将 appDelegate 函数更改为以下内容,但仍然存在相同的问题。我怎样才能保持强大的参考。至 let about = HomeTabBarCoordinator()
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var appCoordinator: TabAppCoordinator?
let tabBarController = UITabBarController()
let about = HomeTabBarCoordinator()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let one = deGenericize(about)
appCoordinator = TabAppCoordinator(tabBarController: tabBarController, tabs: [one])
appCoordinator?.start()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
违规代码:
let about = HomeTabBarCoordinator()
它有什么作用?它创建一个局部变量并在其中存储一个 HomeTabBarCooordinator()
对象。
一旦 application(_:didFinishLaunchingWithOptions)
消失,它会做什么?它当然会取消初始化,因为没有创建新的强引用(声明委托是件好事!)。
你可能认为
public init<T: TabCoordinator>(_ tabCoordinator: T) {
rootController = tabCoordinator.rootController
tabBarItem = tabCoordinator.tabBarItem
}
会救你的。让我们看看 rootController
或 tabBarItem
是否强烈引用我们的 HomeTabBarCoordinator
:
class HomeTabBarCoordinator: NSObject, TabCoordinator {
var rootController: UINavigationController
var tabBarItem: UITabBarItem = UITabBarItem(title: "About", image: UIImage(named: "AboutTabBarIcon"), selectedImage: UIImage(named: "AboutTabBarIcon_Filled"))
let homeVC: HomeViewController
override init() {
self.homeVC = HomeViewController()
self.rootController = UINavigationController()
super.init()
rootController.viewControllers = [homeVC]
rootController.tabBarItem = tabBarItem
homeVC.delegate = self //is being set properly when i add a breakpoint here
}
}
不,他们没有。再见HomeTabBarCoordinator
!所以 delegate
变为零。
How can i keep a strong ref. to let about = HomeTabBarCoordinator()
把它放在一个本身被强引用的class中就足够了。任何未声明 [=37=] 的引用都是强大的,并且在封装 class 存在的情况下将存在。
而且 AppDelegate
可以肯定的是它不会自行取消初始化。