- Published on
๐ Swift - Coordinator ํจํด
- Authors
- Name
- ์ด์ฐฝ์ค
์ง์ง๋ก ์ด ํ๋ก์ ํธ๊ฐ ์ด๋ ๊ฒ ์ด๊ฑฐ์ ๊ฑฐ ๋ง์ด ํด๋ณด๊ฒ ๋ ์ค์ ๋ชฐ๋๋๋ฐ.. ์๋ฌด๋๋ ์ด๊ฑฐ์ ๊ฑฐ ๋๋ฌด ๋ง์ด ํด๋ณด๋๋ผ ์ดํด๊ฐ ๋ถ์กฑํ๊ฒ ๋์ด๊ฐ๋ ๋ถ๋ถ๋ ์๋ ๊ฒ ๊ฐ์์. ๋ง๋ฌด๋ฆฌ ๋๋ฉด ๋ํ์ ํ๋ฒ ํด๋ด์ผ๊ฒ ์ต๋๋ค ๐ญ
์ด๋ฒ์๋ Coordinator ํจํด์ ๋๋ค.
View Controller๊ฐ์ Flow๋ฅผ ์ ์ดํ๋ ๊ฐ์ฒด๋ฅผ ๋์ด์ ๋ทฐ์ปจ๊ฐ์ ์ ํ์ ์์ ์ ์ด๊ณ ์ฝ๊ฒ ๋ง๋๋ ํจํด์ธ๋ฐ์, ์ฌ์ค ์ ํ๋ก์ ํธ์๋ ๋น์ฅ ํ์์ฑ์ ๋ชป๋๋ผ๊ณ ์์ง๋ง ๋ ๋น์ฅ ์ ์ฉํด๋ณผ์ ์๋ ๋ฐ ์ํด๋ณผ ์ ์์ง ์์ต๋๊น? ใ ใ ;;
๊ทธ๋์ ํด๋ณด๊ธฐ๋ก ํ์ต๋๋ค.
์ค๋ ๋์์ ์ป์ ๊ฒ์๋ฌผ์
Coordinator Pattern with Tab Bar Controller
์ ๋ธ๋ก๊ทธ ๊ธ ์ ๋๋ค!
Coordinator Pattern
์ฝ๋๋ค์ดํฐ ํจํด์ด๋?
์ฝ๋๋ค์ดํฐ ํจํด์ด๋ ์์์ ๊ฐ๋ตํ๊ฒ ์ค๋ช ํ๋ฏ์ด
์ฑ์ View Controller๋ค ์ฌ์ด์ Flow Control๊ณผ Navigation์ ๊ด๋ฆฌํด์ฃผ๋ ํจํด์ ๋๋ค. ์ฝ๋๋ค์ดํฐ ํจํด์ ์ฌ์ฉํจ์ผ๋ก์ ํ๋ฉด์ ํ๋ฆ์ ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ณ , ๋ ๋ทฐ๋ฅผ ๋ถ๋ฌ์ค๋ ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ์ ๋ถ์ฌํด์ค๋ค๋ ์ด์ ์ด ์์ต๋๋ค.
์๋์ ๋ฐฉ์
์ ์๋๋ผ๋ฉด View Controller๋ฅผ ๋ถ๋ฌ์ฌ ๋ ์ด๋ค ์์ผ๋ก ํ๋์? ์คํ ๋ฆฌ๋ณด๋๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํ๋ค๋ฉด
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateInitialViewController() as! MainViewController
self.navigationController.pushViewController(mainViewController, animated: true)
์์ฒ๋ผ ์์ฃผ์์ฃผ ๊ธด ์ฝ๋๋ฅผ ์๋ก์ด ๋ทฐ์ปจ์ ๋ถ๋ฌ์ฌ๋๋ง๋ค ์ ๋ ฅํ๊ณ ์คํํด์ผ ํ์ฃ ?
ํ๋ฉด์ด ๋ง์ง ์์ ์ฑ์ด๊ฑฐ๋ ํ๋์ ํ๋ฉด์์ ํ๋์ ํ๋ฉด์ผ๋ก๋ง ๋์ด๊ฐ๋ ๊ฒฝ์ฐ์์ผ ์ ํ ๋ฌธ์ ๊ฐ ๋ ๊ฒ ์์ง๋ง, ํ๋ฉด์ด ์์ฃผ ๋ง๊ณ ํ ํ๋ฉด์์ ์ฌ๋ฌ๊ฐ์ง ํ๋ฉด์ผ๋ก์ ์ ํ์ด ๊ฐ๋ฅํ๋ค๋ฉด ์ ์ฝ๋๋ฅผ ๋ฐ๋ณตํด์ ๊ณ์ ์ ๋ ฅํ์ ๊ฑฐ์์.
์ฝ๋๋ค์ดํฐ๋ฅผ ์ฌ์ฉํ๋ฉด?
import UIKit
// MARK: - Coordinator
protocol Coordinator: class {
var finishDelegate: CoordinatorFinishDelegate? { get set }
// Each coordinator has one navigation controller assigned to it.
var navigationController: UINavigationController { get set }
/// Array to keep tracking of all child coordinators. Most of the time this array will contain only one child coordinator
var childCoordinators: [Coordinator] { get set }
/// Defined flow type.
var type: CoordinatorType { get }
/// A place to put logic to start the flow.
func start()
/// A place to put logic to finish the flow, to clean all children coordinators, and to notify the parent that this coordinator is ready to be deallocated
func finish()
init(_ navigationController: UINavigationController)
}
extension Coordinator {
func finish() {
childCoordinators.removeAll()
finishDelegate?.coordinatorDidFinish(childCoordinator: self)
}
}
// MARK: - CoordinatorOutput
/// Delegate protocol helping parent Coordinator know when its child is ready to be finished.
protocol CoordinatorFinishDelegate: class {
func coordinatorDidFinish(childCoordinator: Coordinator)
}
// MARK: - CoordinatorType
/// Using this structure we can define what type of flow we can use in-app.
enum CoordinatorType {
case app, login, tab
}
๋ค ์์ฒญ ๋ณต์กํด๋ณด์ด์ฃ ..? ๊ทธ๋ฅ ์๋์ ๋ฐฉ์์ ์ฐ๊ณ ์ถ์ด์ง์ฃ ..?
ํ์ง๋ง ํ๋ฒ ๋ฐฐ์๋๋ฉด ๋ถ๋ช ์ ์จ๋จน์๊ฑฐ๋ผ ๋ฏฟ๊ณ ๋ฐฐ์๋ด ์๋ค.
๊ทธ๋์ ์ ๊ฑธ ์ด๋ป๊ฒ ์ฐ์ฃ ?
์ฝ๋๋ค์ดํฐ ํจํด์ ์ฌ์ฉํ๋ ๋ชจ๋ ์ฑ์๋ ์ต์ํ ํ๋์ ์ฝ๋๋ค์ดํฐ๊ฐ ํ์ํฉ๋๋ค. ๋ณดํต ๊ฐ์ฅ ๋ฟ๋ฆฌ๊ฐ ๋๋ ์ฝ๋๋ค์ดํฐ๋ถํฐ ๋ง๋ค๊ธฐ ์์ํ๊ณ , ์ผ๋ฐ์ ์ผ๋ก AppCoordinator๋ผ๊ณ ๋ถ๋ฆ ๋๋ค. ๋ฌผ๋ก ์ฌ๋ฌ๊ฐ์ ์ฝ๋๋ค์ดํฐ๋ฅผ ์ฌ์ฉํ ์ ์์ง๋ง ์ฐ์ ๊ฐ์ฅ ๋ฟ๋ฆฌ๊ฐ ๋๋ ์น๊ตฌ๋ถํฐ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
๋ง์ฐฌ๊ฐ์ง๋ก ๋ณต์กํด๋ณด์ด์ง๋ง ์์ ๋ง๋ค์๋ ํ๋กํ ์ฝ๋๋ก ๋ง๋ ๊ฒ ๋ฟ์ด์์!
๊ทธ๋ฆฌ๊ณ AppCoordinator๋ฅผ initํ๋๋ฐ ๊ฐ์ฅ ์ข์ ๊ณณ์ AppDelegate๋ผ๊ณ ํ๋ค์
์ด AppDelegate๋ผ๋ ๋๋ ํ๋ฒ ์ ๋๋ก ๊ณต๋ถํด๋ด์ผํ๋๋ฐ ์๊ณ ์์๋ค์. ์ด์ฐธ์ ๋ฆฌ์คํธ์ ์ฌ๋ ค๋๊ณ .. ๊ทธ๋ฐ๋ฐ AppDelegate๋ผ๋ ๋์ iOS13 ์ดํ๋ถํฐ SceneDelegate์ ๊ธฐ๋ฅ์ ๋๋์ด๊ฐ๊ฒ ๋์์ต๋๋ค. ๊ฐ๋จํ๊ฒ๋ง ์ค๋ช ๋๋ฆฌ๊ณ ๋์ด๊ฐ์๋ฉด ์ฑ์ ์ง์ ์ง์ ์ ์ ํด์ฃผ๊ณ ์คํ์ํ๋ฅผ ๋ชจ๋ํฐ๋ง ํด์ค๋ค๊ณ ์๊ฐํ์๋ฉด ๋ฉ๋๋ค. (์ฌ์ค ์ ๋ ์ ๋ชฐ๋ผ์ ๐)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow.init(frame: UIScreen.main.bounds)
let navigationController: UINavigationController = .init()
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
appCoordinator = AppCoordinator.init(navigationController)
appCoordinator?.start()
return true
}
๊ทธ๋์ SceneDelegate์ ์๋ ๋ถ๋ถ์ ์ถ๊ฐํด์ ์ฑ ์คํ์์ ์ค์ ํด์ค์๋ค!
์ด์ ์ด ์ฑ์ ์คํ์ํค๋ฉด ์๋ฌด๊ฒ๋ ์๋ ๋น์ด์๋ Navigation Controller๋ง ๋์ฐ๋ ์ฑ์ด ๋์์ต๋๋ค. ํ์ง๋ง ์ฌ์ค์ DefaultAppCoordinator์ start
ํจ์๋ฅผ ์ฝํ์ฌ ์คํ์ํค๊ณ ์์ฃ . ๋จ์ง ์์ง ๊ทธ ๋ถ๋ถ์ ๊ตฌํํ์ง ์์์ ๋ฟ์
๋๋ค.
์ฐ์ ๋์ํ๋ ๊ฒ์ ํ์ธํ๊ธฐ ์ํด ์ด๋ ๊ฒ ์ํ๋ ViewController๋ฅผ pushํด์ฃผ๋ ์ฝ๋๋ฅผ ๋ฃ์ด์ฃผ๋ฉด ํด๋น ๋ทฐ์ปจ์ด ์ฑ ์คํ ์ด๊ธฐํ๋ฉด์ผ๋ก ๋ฑ์ฅํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค!
TabBar + Coordinator ํจํด
์ฝ๋๋ค์ดํฐ ํจํด์ ์กฐ๊ธ ์์ฉํ๋ฉด TabBar์๋ ์ ์ฉ์ ํ ์๊ฐ ์์ต๋๋ค. ์ค๋์ ๋จ์ ์ ์ฉ์ด๊ธฐ ๋๋ฌธ์ ์ฝ๋ ์์ฃผ๋ก ์ฑ์ฑ ์ง๋๊ฐ๊ฒ์!
๋ค๋ฅธ ๊ธฐ๋ณธ์ ์ธ ๋ถ๋ถ์ TabBar ๊ตฌ์ฑ๊ณผ ๋์ผํฉ๋๋ค.
์ค์ํ ๊ณณ์ ๋ฐ๋ก ์ฌ๊ธฐ!
Home์ด๋ผ๋ ํ์ด์ง์๋ Home Coordinator์ start()
๋ฅผ callํด์ ๊ตฌ์ฑํ๋ ๋ถ๋ถ์ด์ฃ ! ๋์์ ์ฝ๋๋ค์ดํฐ ํจํด์ ์ ์ฉ์ํค๊ธฐ ์ํด finishDelegate
๋ ๋ฑ๋กํ๋ฉด์ childCoordinator
์ ํด๋น ์ฝ๋๋ค์ดํฐ๋ฅผ ๋ฑ๋ก์์ผ์ฃผ๋ ์์
๊น์ง ์ด๋ฃจ์ด์ก์ต๋๋ค.
์ด๋ฒ์ Home Coordinator ํ์ผ์ ์ดํด๋ณผ๊น์?
์ด์ ๊ฒ์๋ฌผ์ ์ฝ๋๋ค์ดํฐ์ ๋น์ทํ ๊ตฌ์กฐ๋ฅผ ์ง๋๊ณ ์์ฃ . NavigationController
๋ฅผ ๋ฐ์์ค๊ณ , View Model๋ ๋ฑ๋กํด์ฃผ์์ต๋๋ค.
let homeStoryboard = UIStoryboard(name: "Home", bundle: nil)
let homeVC = homeStoryboard.instantiateViewController(withIdentifier: "HomeVC") as! HomeViewController
self.homeViewController = homeVC
์ด ๋ถ๋ถ์ ์ ๊ฐ storyboard๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ ํธํ๊ธฐ ๋๋ฌธ์ ์ด๋ ๊ฒ ์ฌ์ฉํ์์ต๋๋ค.
์ฝ๋๋ก UI ๊ตฌ์ฑ์ ํ์ค ๋ถ๋ค์
self.homeVC = HomeViewController()
์ด๋ ๊ฒ๋ง ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค!