- Published on
๐ Swift - ์ฝ๋๋ค์ดํฐ ํจํด ์ ๋๋ก ์ดํดํ๊ธฐ
- Authors
- Name
- ์ด์ฐฝ์ค
- Coordinator ํจํด
- Coordinator ํจํด์ด๋?
- ์ธ์คํด์ค ์ง์ ์์ฑ ๋ฌธ์
- ์ฌ์ฌ์ฉ์ฑ ๋ฌธ์
- Coordinator ์ฌ์ฉํ๊ธฐ
- AppCoordinator
- ๊ทธ ์ธ Coordinator
- ๋ง์น๋ฉฐ
- ์ฐธ๊ณ ๋ฌธ์
MusicSpot์ ๊ฐ ํ๋ฉด์ Feature ๋จ์์ ํจํค์ง๋ก ๋ณ๋๋ก ๊ฐ๋ฐํ๊ณ ์์ต๋๋ค.
- ์ฆ๋ถ ๋น๋๊ฐ ๊ฐ๋ฅํด์ง๋ค.
- ๊ฐ Feature๋ง๋ค ๋ณ๋์ ๋ฐ๋ชจ ์ฑ์ ๋ง๋ค ์ ์๊ฒ ๋๋ค.
์ฒซ ๋ฒ์งธ ์ฅ์ ์ ๊ฒฝ์ฐ ์ฌ์ค์ ์ ํฌ๊ฐ ์ฒด๊ฐํ์ง๋ ๋ชปํ๊ณ ์์ต๋๋ค.
๋๊ท๋ชจ ์ฑ์ ์ด์ธ๋ฆฌ๋ ๊ตฌ์กฐ์ธ๋งํผ, ์ฑ์ ๊ท๋ชจ๊ฐ ์์ฃผ ์์ ์ ํฌ ํ๋ก์ ํธ์์๋ ๋๋ผ๊ธฐ ํ๋ ์ฅ์ ์ ๋๋ค.
๋ ๋ฒ์งธ ์ฅ์ ์ด ์ ํฌ๊ฐ ์๊ฐํ๋ ํ์ฌ ํ๊ฒฝ์์ ์ทจํ ์ ์๋ ์ด์ ์ด๋ผ๊ณ ๋ณด๊ณ ์์ต๋๋ค.
๊ทธ๋ฐ๋ฐ, ์ด๋ฐ ์ฅ์ ๋ค์ ๋ฐ๋ผ ๋จ์ ๋ ๋น์ฐํ๊ฒ ํจ๊ป ๋ฐ๋ผ์ค๊ฒ ๋์์ต๋๋ค.
์ต์ข ์ ์ธ ์ฑ ํ๊ฒ ํ๋ก์ ํธ๊ฐ ๊ฐ Feature ํจํค์ง๋ค์ ์์กดํ๊ณ ์ด๋ค์ ์ฐ๊ฒฐ์์ผ์ฃผ์ด์ผ ํ๋ค๋ ์ ์ธ๋ฐ์..
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ํ๋ฉด๋ค์ ๊ด๋ฆฌํ๊ณ ๊ทธ ์ฌ์ด์์ ํ๋ฉด ์ ํ์ ๋ด๋นํ๋ ๋ก์ง์ ๋ณ๋๋ก ๊ตฌํํ ์ ๋ฐ์ ์์์ต๋๋ค.
Coordinator ํจํด
Coordinator ํจํด์ด๋?
Coordinator ํจํด์ ์ ํํ๊ฒ ๋ ๊ฒ์ ๋ฐ๊ฐ์ ์ ์ด์์ต๋๋ค.
๋๋ฌธ์ ์ด ํจํด์ด ์ ๋ฑ์ฅํ๊ณ , ์ ํ์ํ๋ ๊ฑด์ง ๊ณ ๋ฏผํด๋ณด์ง ์์์๋๋ฐ์.. ์ด๊ฒ๋ถํฐ ์์๋ด์ผ ์ ๋๋ก ์ฌ์ฉํ ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค.
// ViewController.swift
let vc = SearchViewController()
self.navigationController?.pushViewController(vc, animated: true)
iOS์์ ์ผ๋ฐ์ ์ผ๋ก ์ด๋ฃจ์ด์ง๋ ํ๋ฉด ์ ํ ๋ก์ง์ ๋๋ค.
ViewController ์ธ์คํด์ค๋ฅผ "์์ฑ" ํ๊ณ ์์์ง ์์์ง ๋ชจ๋ฅด๋ NavigationController
์๊ฒ push
ํด๋ฌ๋ผ๊ณ ์์ฒญํฉ๋๋ค.
์ด ๋ ๋ฐ์ํ๋ ๋ฌธ์ ์ ๋ค์ ์๋์ ๊ฐ์ต๋๋ค.
- Navigation Stack์ ์ถ๊ฐํ ViewController๋ฅผ ์๊ณ ์์ด์ผํ๊ณ , ์ฌ์ง์ด ์ง์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
- ํด๋น ๋ก์ง์ ๋ชจ๋ ํ๋ฉด์์ ๊ฐ๊ธฐ ๋ฐ๋ก ๊ตฌํํด์ค ๋ค ์ฌ์ฉํด์ผ ํ๋ค. ์ฆ, ์ฌ์ฌ์ฉ๋๊ธฐ ์ด๋ ต๋ค.
์ธ์คํด์ค ์ง์ ์์ฑ ๋ฌธ์
๊ธฐ๋ณธ์ ์ธ ๋ฐฉ์๋๋ก AViewController
์์ BViewController
๋ก ํ๋ฉด ์ ํ์ ํ๋ ค๋ฉด A๊ฐ B๋ฅผ ์๊ณ ์์ด์ผ ํฉ๋๋ค.
๊ทธ ๋ง์, A๊ฐ B์ ๊ฐํ๊ฒ ์์กดํ๊ณ ์๋ค๋ ๊ฒ๊ณผ ๋์ผํ ์๋ฏธ์ ๋๋ค.
๊ทธ๋ฐ๋ฐ ์ด ํ๋ก์ ํธ๊ฐ ์ ํฌ ํ๋ก์ ํธ์ฒ๋ผ ๋ชจ๋ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด์?
ํน์ MVVM ๊ตฌ์กฐ๋ฅผ ์ ์ฉํ๋๋ฐ, BViewController์ ์ฃผ์ ํด์ผ ํ ์ธ์คํด์ค๊ฐ ์๋ค๋ฉด์?
let serviceA = ServiceA()
let serviceB = ServiceB()
let viewModel = BViewModel(
serviceA: serviceA,
serviceB: serviceB
)
let vc = BViewController(
viewModel: viewModel,
isCompleted: true
)
View์ ๊ด๋ จ๋ ๋ก์ง๋ง์ ๋ด๊ณ ์ถ์๋ ViewController๊ฐ ๊ฒฐ๊ตญ์๋ ๋น์ฆ๋์ค ๋ก์ง์ ๋ํ ์ ๋ณด๋ฅผ ์์์ผ ํ๊ฒ๋ฉ๋๋ค.
UseCase์ Repository๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ์ด ์ด ์์ฑ๊ณผ ํ๋ฉด ์ ํ์ ๋ํ ๋ก์ง์ ๋ค๋ฅธ ๋ ์ด์ด์ "์์" ํ ์ ์๋ค๋ฉด ์ ๋ง ์ข๊ฒ ์ฃ ?
AViewController๊ฐ BViewController์ ๋ํด ๋ชฐ๋ผ๋ ๋๋ ๋ ๋ฆฝ์ ์ผ๋ก ๋์ํ ์ ์๊ฒ ๋๊ณ , UI์ ๊ด๋ จ๋ ๋ก์ง๋ง์ ์ฒ๋ฆฌํ๋๋ก ์ฑ ์์ ๋ถ๋ฆฌํ ์ ์์ํ ๋๊น์.
์ฌ์ฌ์ฉ์ฑ ๋ฌธ์
์ฌ๊ธฐ AViewController์ BViewController๊ฐ ์ ํํ ๊ฐ์ ๋ก์ง์ ํตํด CViewController๋ฅผ ์์ฑํ๊ณ pushํ๊ณ ์์ต๋๋ค.
์ง๊ธ์ ๋จ์ํ ๋ ๊ฐ์ ๋ทฐ์ปจ๋ง ๋์ดํ์ง๋ง, ๊ฐ๊ธฐ ๋ค๋ฅธ ์ํฉ์์๋ ๊ฐ์ ํํ์ ํ๋ฉด ์ ํ ๋ก์ง์ด ํ์ํ ๊ฒฝ์ฐ๊ฐ ์ฐธ ๋ง์ต๋๋ค.
์ธ์คํ๊ทธ๋จ์ ๊ฒฝ์ฐ๋ฅผ ๋ณด๋๋ผ๋ ๊ฒ์๋ฌผ, ์คํ ๋ฆฌ, ํ๋ก์, ๊ฒ์ ๋ฑ ์์ฃผ ๋ค์ํ ๊ฒฝ๋ก๋ฅผ ํตํด ์ด๋ค ์ ์ ์ ํ๋กํ ํ๋ฉด์ผ๋ก ์ง์ ํ ์ ์์ฃ .
๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ ์ค๋ณต๋๋ ๋์์ ๋ด๋นํ๋ ํ๋์ ๊ณ์ธต์ ๋ง๋ ๋ค๋ฉด ์ฌ์ฌ์ฉ์ฑ์ ์์ฃผ ๋์์ด ๋๊ฒ ์ฃ ?
๊ทธ๋ฌ๊ธฐ ์ํด์๋ ํ์ฌ A, B ๋ฑ ๋ค์ํ ๋ทฐ์ปจ์์ ๊ฐ์ง๊ณ ์๋ ํ๋ฉด ์ ํ ๋ก์ง์ ์ฑ ์์ ๋ค๋ฅธ ํ๋์ ๊ณ์ธต์ "์์" ํด์ค์ผ ํฉ๋๋ค.
ํ๋ฉด ์ ํ์ ์ฑ ์์ ๊ฐ๊ฐ์ ViewController ๋ค์์ Navigator (๊ฐ์นญ) ๊ณ์ธต์ผ๋ก ์ฎ๊น์ผ๋ก์จ ์ด๋ค ViewController๊ฐ ์์ฒญํ๋์ง๋ ์๊ด์์ด ๊ณตํต๋ ๋ก์ง์ ์ฌ์ฉํ ์ ์๊ฒ๋๋ ๊ฒ์ด์ฃ .
์ด ๋ ๋ฌธ์ ๋ ๋ณ๋๋ก ์๊ฐํ ์ ์์ง๋ง ํ๋์ ๊ณตํต์ ์ ๊ฐ๊ณ ์์ต๋๋ค.
๋ฐ๋ก "์์" ์ด๋ผ๋ ํค์๋๋ก ํด๊ฒฐํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ iOS ๊ฐ๋ฐ์์ ์ด ์์์ด๋ผ๋ ํค์๋๋ Delegate ํจํด์ด๋ผ๋ ์์ฃผ ๋ณดํธ์ ์ธ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ ์ ์์ต๋๋ค.
๋ฌผ๋ก ์ด ์ฑ ์์ ์์ํ๋ ๋ฐฉ๋ฒ์๋ ์์ฃผ ๋ง์ ๋ฐฉ๋ฒ๋ค์ด ์๊ฒ ์ง๋ง, ๊ทธ ์ค ๊ฐ์ฅ ์๋ฃ๊ฐ ๋ง์ ๋ฐฉ๋ฒ์ด ๋ฐ๋ก Coordinator ํจํด์ธ ๊ฒ์ ๋๋ค.
๋ช ์นญ์ Coordinator์ด์ง๋ง ์ด๋๊น์ง๋ "ํจํด"์ด๊ธฐ ๋๋ฌธ์ ์ ํํ ๋ ํํ๋ ์๊ฒ ์ง๋ง ๊ฐ์ ๋ชฉ์ ๊ณผ ์๋จ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค๋ฉด ๋ชจ๋ Coordinator ํจํด์ด๋ผ๊ณ ๋ณผ ์ ์๊ฒ ๋ค์.
๊ทธ๋ฌ๋๊น Coordinator ํจํด์ ํ๋ฉด ์ ํ์ ํนํ๋ Delegate ๋ฐฉ์ ์ค ํ๋๋ผ๊ณ ๋ณผ ์ ์๊ฒ ๋ค์.
Coordinator ์ฌ์ฉํ๊ธฐ
์ด์ Coordinator ํจํด์ด Delegate ํจํด ์ค ํ๋๋ผ๋ ๋๋์ ์ ๋ ํด๊ฐ๋ฉฐ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Coordinator ํจํด์ ์ฒ์ ์ดํดํ ๋๋ ๊ฐ ViewController๋ง๋ค ํ๋์ Coordinator๋ฅผ ์ฌ์ฉํ๋ค๊ณ ์ดํดํ๋ฉด ํธํฉ๋๋ค.
๋น์ฐํ๊ฒ๋ ๋งค๋ฒ ๊ทธ๋ ์ง๋ ์์ต๋๋ค. ๋ฐ๋ณต๋๋ ํ๋ฉด ์ ํ์ ํ๋ฆ์ด ์๋ค๋ฉด, ์ด๋ฅผ Flow๋ผ๋ ๋จ์๋ก ์ ์ํ๊ณ Coordinator๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด HomeViewController์์ SearchViewController๋ก์ ์ ํ์ด ํ์ํ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด๋ณด๊ฒ ์ต๋๋ค.
- HomeViewController์ Coordinator์ธ
HomeCoordinator
์ ํ๋ฉด ์ ํ์ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค. HomeCoordinator
๋ SearchViewController์ ๋ํ ์ฑ ์์ด ์๋SearchCoordinator
๋ฅผ ์์ฑํฉ๋๋ค.SearchCoordinator
์๊ฒ SearchViewController ์ธ์คํด์ค ์์ฑ๊ณผ push ๋ก์ง์ ์คํ์ ์์ฒญํฉ๋๋ค.SearchCoordinator
๊ฐ SearchViewController๋ฅผ ์์ฑํ๊ณ Navigation Stack์push
ํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ธ ํ๋ฆ์ ์ฌ๊ธฐ์์ ํฌ๊ฒ ๋ฒ์ด๋์ง ์์ต๋๋ค.
ViewController๋ ์์ ์ ์์ฑํ(๊ด๋ฆฌํ๋) Coordinator์๊ฒ ํ๋ฉด ์ ํ์ ์์ฒญํฉ๋๋ค.
๊ทธ๋ฌ๋ฉด ํด๋น Coordinator๋ ๋ค๋ฅธ Coordinator๋ฅผ start()
์ํค๊ฑฐ๋ Flow ํ๋ฆ์ ๋ฐ๋ผ ViewController๋ฅผ Navigation Stack์ ์ถ๊ฐํฉ๋๋ค.
protocol Coordinator: AnyObject {
var navigationController: UINavigationController { get set }
var childCoordinators: [Coordinator] { get set }
var finishDelegate: CoordinatorFinishDelegate? { get set }
func start()
func finish()
}
๊ทธ๋ฆฌ๊ณ ์ ์์๊ฐ ์ด ํ๋ฆ์ ๋ฐ๋ผ ํ์ํ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํํ์ Protocol์ ๋๋ค.
AppCoordinator
Coordinator ํจํด์ childCoordinators
๋ฐฐ์ด๋ก ํ์ Coordinator๋ฅผ ๊ด๋ฆฌํ๋ ์ผ์ข
์ ํธ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
๊ทธ ๋ง์ ๊ณง, ์ต์๋จ์ ๋ฟ๋ฆฌ๊ฐ ํ๋ ์์ด์ผํ๋ค๋ ์๋ฏธ์ ๋๋ค.
์ด ๋ฟ๋ฆฌ๊ฐ ๋ฐ๋ก AppCoordinator์ ๋๋ค.
์ด AppCoordinator๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๋ฉฐ ๋๋ต์ ์ธ Coordinator์ ์ฌ์ฉ๋ฒ์ ์์๋ด ์๋ค.
var window: UIWindow?
var appCoordinator: AppCoordinator?
func scene(_ scene: UIScene,
willConnectTo _: UISceneSession,
options _: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
defer { self.window = window }
let navigationController = UINavigationController()
self.appCoordinator = AppCoordinator(navigationController: navigationController)
window.rootViewController = navigationController
window.makeKeyAndVisible()
self.appCoordinator?.start() // โ
}
์ด๋ ๊ฒ UINavigationController
๋ฅผ ํ๋ ๋ง๋ค์ด Coordinator์ ์ ๋ฌํด์ฃผ๋ ์์ผ๋ก ์ธ์คํด์ค๋ฅผ ์์ฑํด ์ฌ์ฉํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ Coordinator์ start()
ํจ์๋ฅผ ํธ์ถํด์ฃผ๋ ๊ฒ์ผ๋ก ๋ด๋นํ๋ ViewController๋ฅผ ์์ฑํ๊ณ ์ด๋ํ๋ ๋ก์ง์ ์ํํ๊ฒ ๋ฉ๋๋ค.
๊ทธ ์ธ Coordinator
// HomeCoordinator.swift
func startSearch() {
let searchCoordinator = SearchCoordinator(navigationController: self.navigationController)
searchCoordinator.finishDelegate = self // 1๏ธโฃ
self.childCoordinators.append(searchCoordinator) // 2๏ธโฃ
searchCoordinator.start() // 3๏ธโฃ
}
๋ค๋ฅธ Coordinator๋ฅผ ์์ฑํ๊ณ start()
ํด์ฃผ๋ ๊ณผ์ ์ ์ ๊ณผ์ ์์ ํฌ๊ฒ ๋ฒ์ด๋์ง ์์ต๋๋ค.
1๏ธโฃ ์์ฑ๋ Coordinator์ ์์ Coordinator๊ฐ ๋ณธ์ธ์์ ์๋ฆฌ๊ธฐ ์ํด Delegate ํจํด์ ์ฌ์ฉํฉ๋๋ค. ์ดํ์ finish()
๋ฅผ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
2๏ธโฃ ์์ฑ๋ Coordinator๋ฅผ ์์ Coordinator์์ ์ฐธ์กฐํจ์ผ๋ก์จ ARC๊ฐ ์๋์ผ๋ก ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ์ํค์ง ์๋๋ก ์ ์งํด์ค๋๋ค.
3๏ธโฃ ์์ฑ๋ Coordinator์ start ๋ก์ง์ ์คํํฉ๋๋ค.
๋ฐ๋๋ก finish()
ํด์ฃผ๋ ๊ณผ์ ์ CoordinatorFinishDelegate
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
extension Coordinator {
func finish() {
self.childCoordinators.removeAll() // 1๏ธโฃ
self.finishDelegate?.shouldFinish(childCoordinator: self) // 2๏ธโฃ
}
}
1๏ธโฃ ํ์ Coordinator๋ค์ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ์์ผ์ฃผ๊ธฐ ์ํด childCoordinators
๋ฐฐ์ด์ ๋น์์ค๋๋ค.
2๏ธโฃ ์์ Coordinator์๊ฒ Delegate ํจํด์ ์ฌ์ฉํด ์ข ๋ฃ ์์ฒญ์ ํฉ๋๋ค.
๋ง์น๋ฉฐ
์ด๋ ๊ฒ ๋ฐ๊ฐ์ (?)๋ก Coordinator์ ๋ํด์ ๋ค์ ํ ๋ฒ ์๊ฐํด๋ณด๋ ์๊ฐ์ ๊ฐ์ก์ต๋๋ค.
๋ฌด์๋ณด๋ค ์ค์ํ ๊ฒ์ "Coordinator ํจํด์ ํ๋ฉด ์ ํ ๋ก์ง์ ์ฑ ์ ๋ถ๋ฆฌ๋ฅผ ์ํ Delegate ํจํด์ ์ผ์ข ์ด๋ค." ๋ผ๋ ์ฌ์ค์ธ ๊ฒ ๊ฐ์ต๋๋ค.
๋ํ, ๋ง ๊ทธ๋๋ก ํจํด์ผ ๋ฟ์ด๊ธฐ ๋๋ฌธ์ ์ ๋ต ๋ํ ์๋ ๊ฐ๋ ์ ๋๋ค.
์ด ํฌ์คํธ์์๋ Delegate ํจํด์ ์ฌ์ฉํด finish
์ ๋ํ ๋ก์ง์ ์ฒ๋ฆฌํด์คฌ๋๋ฐ, RxSwift๋ Combine๊ณผ ๊ฐ์ ๋ค๋ฅธ ์๋ฃจ์
์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
๋ฉํ ๋ง ์๊ฐ์ Coordinator ํจํด์ ๋จ์ ๋ํ ๋ช ํํ๊ธฐ ๋๋ฌธ์ ๊ณ ๋ฏผ์ด ํ์ํ๋ค๊ณ ํด์ฃผ์ จ๋๋ฐ, ์ด ๋จ์ ์ ์์ง ์ฒด๊ฐํ์ง ๋ชปํ์ต๋๋ค.
์ง์ ๋ค์ ์ฌ์ธํ๊ฒ ์ฌ์ฉํด๋ณด๋ฉฐ ๋๋ ์ ์์์ผ๋ฉด ์ข๊ฒ ๋ค์ ๐