Делегат AppCoordinator через контроллеры представления - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь узнать, как работает шаблон координатора, хотя у меня возникли некоторые проблемы с делегатами от одного дочернего контроллера представления координатора к другому. Например, у меня есть домашний видеомагнитофон, и я хочу перейти к деталям с помощью одной кнопки, но я бы хотел, чтобы это управлялось из 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 (см. Комментарии в коде). Есть идеи?

ОБНОВЛЕНИЕ

, как @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
    }

1 Ответ

0 голосов
/ 07 сентября 2018

Код обидчика:

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 становится нулем.

Как мне сохранить сильный реф. чтобы сообщить о = HomeTabBarCoordinator ()

Достаточно поместить его в класс, на который ссылаются сами. Любая ссылка, которая не объявлена ​​слабой / неизвестной, является сильной и будет существовать в том случае, если выживающий класс будет существовать.

И AppDelegate настолько уверен, насколько это возможно, что он не прекратит сам по себе.

...