๐๐ ๊ฐ๋ฐ์ {์จ๋น๋, ์ปจํผ๋ฐ์ค, ํด์ปคํค} ํ์ฌ๋ฅผ iOS ์ฑ์ผ๋ก ์๋ ค๋๋ฆฝ๋๋ค.
- Language: Swift 5.5.2
- iOS Deployment Target: iOS 13.0 +
- Xcode: 13.0 compatible
- CocoaPods
- CoreData
- MVVM
- RxSwift
- Unit Test
-
๋ค๋ชจ ์์๋ก ํํ๋ coordinator์ protocol Coordinator์ ์ค์ํฉ๋๋ค
-
View Controller๋ ์ผ๋์ผ๋ก ๋งค์นญ๋๋ coordinator๊ฐ ์์ผ๋ฉฐ ๋ทฐ ์ ํ์ ์ผ์ coordinator์๊ฒ ์ ๋ดํด ๋ก์ง์ ๋ถ๋ฆฌ์์ผฐ์ต๋๋ค
ํ์ฌ ํ๋ก์ ํธ์์๋ ๋ทฐ ์ ํ ์๋๋ฆฌ์ค๊ฐ ๋จ์ํฉ๋๋ค. ๋ทฐ ์ ํ์ด ๋ณต์กํ๊ณ ๋ค์ํ ์๋๋ฆฌ์ค์์ ์ฌ์ฉํ๋ค๋ฉด View Controller์์ ๋ทฐ ์ ํ ๋ก์ง์ ๋ฐ๋ก ๋ถ๋ฆฌํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋์ ๊ฐ์น๊ฐ ๋์ ๊ฒ์ด๋ผ ์๊ฐํฉ๋๋ค. ํ์ต์ ์์๋ฅผ ๋๊ณ ์ฌ์ฉํ์์ต๋๋ค.
-
View Controller๋ View๋ฅผ ์์ ํ๊ณ ์์ผ๋ฉฐ ๋์ ๊ธด๋ฐํ๊ฒ ์ฎ์ฌ์์ต๋๋ค
-
View Controller๋ ViewModel์ ์์ ํ๋ฉฐ ๋์ Input๊ณผ Output์ ํตํด ์ํตํฉ๋๋ค
-
View Controller๋ ViewModel์ input์ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ก์ ์ ์๊ตฌํ๊ณ ViewModel์ Output์ ํตํด Model์์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ์ฌ ์ ๋ฌํฉ๋๋ค
-
ViewModel์ Input๊ณผ Output์ struct ํํ์ ๋๋ค. ViewModel์ ๋ฐ์ดํฐ ๊ด๋ จ ํ๋กํผํฐ๋ค์ ๋ชจ๋ private์ผ๋ก ์ค์ ๋์ด ์์ต๋๋ค. View Controller์์๋ ํจ์ transform(input:) ์ ํตํด output์ ์ป์ด ์ฌ์ฉํ ์ ์์ต๋๋ค.
Intput, Output์ ๋์ ํ๊ธฐ ์ด์ ์๋ ViewModel์ ํ๋กํผํฐ๋ค์ด public์ผ๋ก ๊ณต๊ฐ๋์ด ์์ด View Controller๊ฐ ์์๋ก ์ ๊ทผ์ด ๊ฐ๋ฅํด ๋ฐ์ดํฐ ๋ณ์ง ์ฐ๋ ค๊ฐ ์์์ต๋๋ค. ์ด ๋ถ๋ถ์ ๊ณ ๋ฏผํ๋ค๊ฐ Input/Output ๊ตฌ์กฐ๋ฅผ ๋ง์ด ์ด์ฉํ๋ ๊ฒ์ ์๊ฒ ๋์๊ณ ์ ์ฉํ์์ต๋๋ค. ๊ทธ ๊ฒฐ๊ณผ, ViewModel์ ํ๋กํผํฐ๋ค์ privateํ๊ฒ ์ค์ ๋์ด ๋ฐ์ดํฐ์ ์์ ์ฑ์ ๋ณด์ฅํ ์ ์์๊ณ , ๋๋ถ์ด ํจ์ transform(input:) ๋ฅผ ํตํด ๋ก์ง์ ๋ถ๋ฆฌ์์ผ ๋ฐ์ดํฐ ํ๋ฆ์ ํ์ ํ๊ธฐ ์ฌ์์ก์ต๋๋ค. (ViewModel์์ ๋ฟ๋ง ์๋๋ผ RxSwift๋ฅผ ์ด์ฉํ์ฌ ๋ฐ์ธ๋ฉ๋๋ ์ฝ๋์์๋ Input/Output์ ์ฌ์ฉํ์์ต๋๋ค)
// HomeViewController.swift
final class HomeViewModel: ViewModelType {
struct Input {
var requestFetchingEvents: Observable<Void>
}
struct Output {
var dataSources: Observable<[SectionOfEvents]>
var isNetworkConnect: Observable<Bool>
}
private let eventsFromServer: BehaviorRelay<[SectionOfEvents]> = BehaviorRelay(value: [])
private let favoriteEvents: BehaviorRelay<[EventCoreData]> = BehaviorRelay(value: [])
func transform(input: Input) -> Output {
...
return Output(dataSources: ..., isNetworkConnect: ...)
}
}
// HomeViewModel.swift
final class HomeViewController: UIViewController {
let viewModel = HomeViewModel()
func bindViewModel() {
let input = HomeViewModel.Input(requestFetchingEvents: requestFetchingEvents.asObservable())
let output = viewModel.transform(input: input)
...
}
}
-
NetworkService๋ฅผ ํตํด ์๋ฒ์์ html ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต๋๋ค
-
DevEventsFetcher์์ ๊ฐ์ ธ์จ String ๊ฐ์ธ html์ ํ์ฑํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํฉ๋๋ค
-
DevEventsFetcher๋ ์ฑ๊ธํค ๊ฐ์ฒด์ด๋ฏ๋ก ๋ฐ์ดํฐ๊ฐ ์ ๋ฐ์ดํธ ๋ ๋๋ง๋ค ์ด๋ฅผ ๊ตฌ๋ ํ๊ณ ์๋ ๋ชจ๋ ViewModel๋ค์๊ฒ ์๋ ค์ค๋๋ค
-
CoreData์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ณ ์ ์ฅํ๋ PersistanceManager๋ฅผ ์ฑ๊ธํด ๊ฐ์ฒด๋ก ๋์ด ๊ด๋ฆฌํฉ๋๋ค
๊ฐ๋ฐ ์ด๊ธฐ์๋ ์ฑ๊ธํด์ผ๋ก ๊ตฌํํ๋ค๊ฐ ์ ๋ ํ ์คํธ๋ฅผ ๋์ ํ๋ฉฐ DevEventsFetcher์์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋๋ก ๋ณ๊ฒฝํ์์ต๋๋ค. ํ๋ก์ ํธ์์ ๋คํธ์ํฌ๋ฅผ ๋ด๋นํ๋ ๊ฒ์ NetworkService ํด๋์ค ํ๋๋ก ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ฒ ํ๊ธฐ ์ํ์ฌ ์ฑ๊ธํด์ผ๋ก ์ค๊ณํ์์ผ๋, ํ์ฌ DevEventsFetcher์์๋ง ๋คํธ์ํฌ ํต์ ์ด ์ผ์ด๋๋ฉฐ ์ ๋ํ ์คํธ ๋ mockURLSession์ ๋ง๋๋๋ฐ ์ด๋ ค์์ด ์์์ต๋๋ค. ์ ๋ํ ์คํธ๋ฅผ ๋์ ํ๋ฉด์ ์ฑ๊ธํด์ด ์๋ ๋จ์ ํด๋์ค๋ก ๋ณ๊ฒฝํ์์ต๋๋ค.
์ฑ๊ธํด ํด๋์ค์ธ NetworkConnectionManager๋ฅผ ๋์ด ์ฌ์ฉ์์ ๊ธฐ๊ธฐ๊ฐ ๋คํธ์ํฌ์ ์ฐ๊ฒฐ๋์ด์๋์ง ๊ฐ์ํ๋ ์ญํ ์ ํฉ๋๋ค. ์ฑ์ด ์คํ๋ ๋ ์๋์ผ๋ก ๋ชจ๋ํฐ๋ง์ด ์คํ๋๋ฉฐ, ViewModel๋ค์ด ๋คํธ์ํฌ ์ฐ๊ฒฐ ์ฌ๋ถ๋ฅผ ๊ตฌ๋ ํ๊ณ ์์ด ์ํฉ์ ๋ง๊ฒ ์ฒ๋ฆฌํด์ค๋๋ค.
- v1.0.4 iOS16์์ ๋ฐ์ํ๋ ๋ฒ๊ทธ ๊ฐ์
- v1.0.3 ์ฆ๊ฒจ์ฐพ๊ธฐํ ์ด๋ฒคํธ ๋ชฉ๋ก์์ ์ข ๋ฃ๋ ์ด๋ฒคํธ section ์ถ๊ฐ
- v1.0.2 ๋ณ ๋ชจ์ ์ด๋ฏธ์ง ์ค์์ ๋ ฌ ๋ฐ ๋ฆฌํฉํฐ๋ง
- v1.0.1 ๋คํฌ๋ชจ๋ ๋์์ธ ๊ฐ์ ๋ฐ ๋ฆฌํฉํฐ๋ง
- v1.0 ์ฑ ์คํ ์ด ์ถ์ (22.04.11)