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 提到的 HomeTabBarCoordinatordidFinishLaunchingWithOptions 中解除分配,我将 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
}

会救你的。让我们看看 rootControllertabBarItem 是否强烈引用我们的 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 可以肯定的是它不会自行取消初始化。