İçeriğe geç

Coordinator Pattern

Merhabalar, bu yazımda sizlere iOS uygulamalarınızı daha kaliteli hale getirecek olan Coordinator tasarım deseni kullanımını paylaşacağım.

Tasarım desenleri bildiğimiz gibi kodlarımızı daha kaliteli, daha efektif ve daha bir çok avantajlar sağlamakta. Bugün sizlere paylaşacağım desen ise Coordinator olarak adlandırılmakta. İsmindende anlaşılacağı üzre koordine etme amacı taşıyan bir tasarım deseni. Bu tasarım deseninin amacı ve mantığı neticesinde en uygun olarak iOS uygulamalarımızda sürekli olarak gerçekleştirdiğimiz ViewController arası gidiş, geliş olaylarını düzenli bir şekilde koordine edebiliriz. Buda bize karmaşık uygulamalarda basitlik kazandırır.

iOS ile VC push işlemleri gerçekleştirirken UINavigationController ve UITabBarController kullanırız. Ben bugün paylaşacağım örnekte uygulamamızda kullandığımız UINavigationController üzerinden bir koordine işlemi göreceğiz.

Lafı fazla uzatmadan olayı kod üzerinde görelim.

Bu işlem için Swift dilinde bulunan Protocol, Delegate işbirliği bizim için oldukça önemli.

protocol Coordinator: class {
    var childCoordinators: [Coordinator] { get set }
    var navigationController: UINavigationController { get set }
    func start()
    func addChild(coordinator: Coordinator)
    func removeChild(coordinator: Coordinator)
}

Koordinator sınıflarımıza bağlanacak bir protokol ve içerisinde bulunması gereken değişken ve fonksiyonları yazdık.

extension Coordinator {
    func addChild(coordinator: Coordinator) {
        childCoordinators.append(coordinator)
    }
    func removeChild(coordinator: Coordinator) {
        childCoordinators = childCoordinators.filter {$0 !== coordinator}
    }
}

Bu protokolde her sınıf için gerçekleşecek aksiyonlar olan addChild ve removeChild için bir extension ekledik. (Direk bağlı sınıf içerisindede yazabilirsiniz.)

class MainCordinator: NSObject, Coordinator {

    var childCoordinators: [Coordinator] = []
    var navigationController: UINavigationController
    
    init(navController: UINavigationController) {
        self.navigationController = navController
    }
    
    func start() {
        let vc = ViewController.instantiate()
        vc.coordinator = self
        navigationController.delegate = self
        navigationController.pushViewController(vc, animated: true)
    }
    
    func goSecondPage() {
        let vc = SecondVC.instantiate()
        vc.coordinator = self
        navigationController.pushViewController(vc, animated: true)
        addChild(coordinator: vc.coordinator!)
    }
    
    func goThirdPage() {
        let vc = ThVC.instantiate()
        vc.coordinator = self
        navigationController.pushViewController(vc, animated: true)
        addChild(coordinator: vc.coordinator!)
    }
}

Yukarda basit bir MainCoordinator sınıfı yazdık. Bu sınıf root bir nav a bağlı vc ile başlayıp devam edecek şekilde olacak. Bunun için gerekli kodları AppDelegate üzerinde başlatalım.

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var coordinator: MainCordinator?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        let navController = UINavigationController()
        coordinator = MainCordinator(navController: navController)
        coordinator?.start()
        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = navController
        window?.makeKeyAndVisible()
     
        return true
    }
}

.start fonksiyonu içerisinde bulunan ViewController sizin root olarak belirlediğiniz bir vc. ve buradaki ViewController.instantiate() fonksiyonu extension olarak yazdığımız olayı daha kolay hale getirmek adına VC isim alıp döndüren bir fonksiyon. Buna bağlı olan protokolü VC sınıflarınıza eklemeniz gerekli ve storyboard id sınıf isminiz ile aynı olmalı.

protocol Storyboarded {
    static func instantiate() -> Self
}

extension Storyboarded where Self: UIViewController {
    static func instantiate() -> Self {
        let fullName = NSStringFromClass(self)
        let className = fullName.components(separatedBy: ".")[1]
        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
        return storyboard.instantiateViewController(withIdentifier: className) as! Self
    }
}

Daha sonra gerekli VC sınıfınız aşağıdaki şekilde diğer sayfaya Coordinator sınıfı ile ilerleyecektir.

class ViewController: UIViewController, Storyboarded {
    
    weak var coordinator: MainCordinator?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        coordinator?.goSecondPage()
    }
}

Bundan sonraki yazımda back işlemi için gerçekleştirmemiz gereken olayları sizlerle paylaşacağım.

Uygulamalarda gerçeklenebilecek oldukça yararlı bir tasarım deseni olduğunu düşünüyorum, kullanmanızı tavsiye ederim 🙂

İlgilenenler için Reactive olarak yazılmış Coordinator tasarım desenini kullanan RxCoordinator kütüphanesini inceleyebilirsiniz.

Yazının Devamı için Coordinator – Part 2

 

 

Tarih:Design Patterns

Bu yazı yorumlara kapalı.

Copyright © 2020 Kenan Atmaca