๐ป ๊ฐ๋ฐ
[Architecture] MVVM + Clean Architecture๋ฅผ ์์๋ณด์
SwiftUI ํน์ฑ์ ViewModel์ ๋ถ๋ฆฌํ๋๊ฒ ๋งค์ฐ ์ฝ๋ค. @ObservedObject ์งฑ์งฑ! ๋๋ถ์ ์ค์ต์ ์งํํ๋ฉด์ ๋๋ถ๋ถ์ ํ๋ก์ ํธ์์ ViewModel๋ก ๋ถ๋ฆฌ๋ ํ์ง๋ง ๋ฌธ์ ๊ฐ ๋ง์๋ค. Massive ViewModel์ด๋๊น? ๊ทธ๋์ ํด์ปคํค ๋๋ ์ด๋ฐ ๊ฒ๋ค์ ๊ฑท์ด๋ด๊ณ ์ํคํ ์ณ์ ์ผ๋ก ์กฐ๊ธ ๋ ๊ด์ฐฎ์ ์ฑ์ ๊ตฌํํ๊ณ ์ถ์๋ค. ๋คํํ๋ ํ์ ์ค ํ ๋ถ์ด ํด๋ฆฐ ์ํคํ ์ณ์ ๋ํด ์ ์๊ณ ๊ณ์ ์ ๋์์ ๋ง์ด ๋ฐ์๊ณ , ์ ๋ณด๋ค๋ ์ด๋์ ๋ ์์ฑ๋ ์ฑ์ ๋ง๋ค ์ ์์๋ค. ์๋ก ์ด ๊ธธ์์ง๋ง ์๋ฌดํผ ํด์ปคํค์ ๊ณ๊ธฐ๋ก Clean Architecure์ ๋ํด ๋ค์ ๊ณต๋ถํ๊ณ ์ถ์ด์ ์ ์ ๋ถ๋งํฌํด๋ ๊ธ์ ๋ณด๋ฉด์ ๊ฐ๋ ์ ์ ๋ฆฌํด๋ณด๋ ์๊ฐ์ ๊ฐ์ก๋ค. Clean Architecture and MVVM on iOS When we deve..
[iOS / SwiftUI] MapKit, ์ค์๊ฐ์ผ๋ก ๋๋ก๋ช ์ฃผ์ ๋ณํํ๊ธฐ
23.01.13 - ์ฑ์ ์ฒ์ ์ค์นํ์ ๋ ํ์ฌ ์์น๋ก ์ด๋ํ์ง ์๋ ์ค๋ฅ ํด๊ฒฐ ์ง๋ ๋ฒ ํ๋กํ ํ์ ์ ์ด์ด ์ด๋ฒ ์ฃผ๋ถํฐ๋ MVP๋ฅผ ์งํํ๊ณ ์๋ค. ๊ธฐ์กด์ ๋๋ฏธ ๋ฐ์ดํฐ๋ก ๊ตฌํํ๋ ๊ฒ๋ค์ ์ค์ FireStore์ ์ฐ๋ํ๊ณ ๊ตฌํํ์ง ๋ชปํ๋ ๋ถ๋ถ๋ค์ ๊ตฌํํ๋ ๊ฒ์ ๋ชฉํ๋ก ์ก์๋ค. ์ด๋ฒ ์ฃผ์ ๊ตฌํํ๋ ค๋ ๊ธฐ๋ฅ์ ์๋์ ๊ฐ๋ค. 1. ์ฌ์ฉ์๊ฐ ์ง๋๋ฅผ ์์ง์ด๋ฉด ์์ง์ธ ์ขํ์ ๋ํ ๋๋ก๋ช ์ฃผ์๋ฅผ ์ค์๊ฐ์ ๊ฐ์ ธ์ด 2. ์ฌ์ฉ์๊ฐ ์ง๋๋ฅผ ์์ง์ด๋ฉด ๋ง์ปค๊ฐ ์ด์ง ์๋ก ์ฌ๋ผ๊ฐ๊ณ , ์์ง์์ด ๋ฉ์ถ๋ฉด ๋ง์ปค๊ฐ ๋ค์ ๋ด๋ ค์ด 3. ์ฌ์ฉ์์ ํ์ฌ ์์น๋ฅผ ๊ฐ์ ธ์ค๊ณ , ๋ฒํผ์ ํด๋ฆญํ๋ฉด ํ์ฌ ์์น๋ก ์ง๋์ Focus๋ฅผ ๋ณ๊ฒฝํจ ํ๋์ฉ ์ดํด๋ณด๋๋ก ํ์. 1. ์ฌ์ฉ์๊ฐ ์ง๋๋ฅผ ์์ง์ด๋ฉด ์์ง์ธ ์ขํ์ ๋ํ ๋๋ก๋ช ์ฃผ์๋ฅผ ์ค์๊ฐ์ผ๋ก ๊ฐ์ ธ์ค๊ธฐ ๋ง์ด ์ข ๊ธธ๋ค. ๊ฐ..
[iOS / SwiftUI] OnAppear, OnDisappear๋ ์ธ์ ํธ์ถ๋ ๊น?
SwiftUI๋ก ๊ฐ๋ฐ์ ์งํํ๋ค๊ฐ View ๋ด๋ถ์์ ์ง์ ์ ์ผ๋ก ํ๋กํผํฐ์ ์ ๊ทผํ ๋ onAppear๋ฅผ ํ ๋ฒ์ฏค์ ์ฌ์ฉํ ๊ฒฝํ์ด ์์ ๊ฒ์ด๋ค. ๊ฐ๋ น, print(ํ๋กํผํฐ)์ฒ๋ผ View ๋ด๋ถ์์ ์ ๊ทผํ๋ฉด ์ด๋ฐ ์๋ฌ๊ฐ ๋ฌ๋ค. View๋ฅผ ๋ฐํํด๋ฌ๋ผ๋ ์๋ฌ๋ค. ์ด๋ฐ ์๋ฌ์ ๋ง์ฃผ์น์ง ์๊ธฐ ์ํด View ๋ด๋ถ์์ ์ง์ ์ ์ผ๋ก ์ ๊ทผํ์ง ์๊ณ , onAppear ํด๋ก์ ๋ด๋ถ์์ ์ ๊ทผํ๋ ๋ฐฉ์์ ํํ๋ค. ์๋ฌดํผ ์ด๋ด ๋ ์์ฃผ ์ฌ์ฉํ๋ onAppear๋ SwiftUI View Life Cycle์ ์ํ๊ณ , ์ค๋์ Life Cycle์ ๋ํด ์์๋ณด๋ ค๊ณ ํ๋ค. SwiftUI์์ 3๊ฐ์ Life Cycle์ด ์๊ณ , ๊ฐ๊ฐ์ Appear, Update, Disappear ์ด๋ค. 1. onAppear onAppear์ View๊ฐ ๋ณด์ฌ์ง๊ธฐ..
[์๋ฌ์์ ๋์นจ] 22๋ 11์ 4์ฃผ์ฐจ
22.11.21 json์ ์กด์ฌํ๋ key, value๋ฅผ struct์์ ์ ์ํ์ง ์์ ๊ฒฝ์ฐ์๋ ์ ์์ ์ผ๋ก Decoding ๋ฐ๋๋ก json์ ์กด์ฌํ์ง ์๋ key, value๋ฅผ struct์์ ์ ์ํ๋ ๊ฒฝ์ฐ์๋ KeyNotFound Error๊ฐ ๋ฐ์ ํน์ value์ key-value๊ฐ ๋ถ๋ถ์ ์ผ๋ก ์กด์ฌํ ๋๋ Optional์ ์ ์ฉ ๋ง์ฝ, key-value๋ฅผ ์ ๋๋ก ์ ์ํ๋๋ฐ KeyNotFound Error๊ฐ ๋ฐ์ํ๋ฉด ํน์ key-value๊ฐ ๋ถ๋ถ์ ์ผ๋ก ์กด์ฌํ๋์ง ํ์ธํ ๊ฒ 22.11.22 json์๋ id๊ฐ ์์ง๋ง identifiable์ ๋ง์กฑ์ํค๊ธฐ ์ํด uuid๋ฅผ ๋ฃ์ด์ฃผ๋ ๊ฒฝ์ฐ var์ด ์๋ let์ผ๋ก ์ ์ธ EnvironmentObject๋ฅผ ์ฌ์ฉํ ๋, ์ต์๋จ์์ ์ธ์คํด์ค๋ฅผ ๋ฃ์ด์ฃผ๊ธฐ์ ๋ทฐ์ ๊ฒ์ธต ๊ตฌ์กฐ..
[iOS / SwiftUI] ์คํฌ๋กค, ๋ฌดํ์ผ๋ก ์ฆ๊ฒจ์~ (LazyVStack์ผ๋ก ๋ฌดํ ์คํฌ๋กค ๊ตฌํํ๊ธฐ)
์ค๋์ ScrollView์ LazyVStack์ ํ์ฉํ์ฌ SwiftUI์์ ๋ฌดํ ์คํฌ๋กค์ ๊ตฌํํด๋ณด๋ ค๊ณ ํ๋ค. ์ฌ์ค, LazyVStack์ด ์กฐ๊ธ ์์ํ ์ ์๋ค. LazyVStack์ ๋ง ๊ทธ๋๋ก Lazyํ๊ฒ VStack์ ๊ทธ๋ฆฐ๋ค๋ ๋๋์ผ๋ก, VStack์ผ๋ก ๋ณด์ฌ์ค ํญ๋ชฉ์ด ์ค์ ๋ก UI์ ๋ณด์ฌ์ง ๋ ๋ ๋๋ง์ ์งํํ๋ View์ด๋ค. Apple Developer Documentation developer.apple.com ๊ทธ๋ ๋ค๋ฉด ๊ธฐ์กด์ ์ฌ์ฉํ๋ VStack๊ณผ๋ ์ด๋ค ์ฐจ์ด๊ฐ ์์๊น? ํ์์ ์ฌ์ฉํ๋ VStack์ ๋ทฐ๊ฐ ๋ณด์ฌ์ง ๋(onAppear) ๋ชจ๋ ํญ๋ชฉ์ ๋ ๋๋งํ๋ค. ๊ทธ๋ ๊ธฐ์ ScrollView + VStack ์กฐํฉ์ผ๋ก List๋ฅผ ๋ํ๋ธ๋ค๋ฉด ์ด๊ธฐ์ ๋ง์ ๋ฆฌ์์ค๋ฅผ ์๋ชจํ๊ฒ ๋๋ค. ์ ์ ๊ฐ์์ ๊ฐ๋จํ ํญ๋ชฉ๋ค์ ..
[iOS / Swift] Swift ๋ฌธ์์ด ์ ๋ณตํ๊ธฐ (aka 'Character')
Swift๋ก ๋ฌธ์์ด ๋ฌธ์ ๋ฅผ ํ๋ค๋ณด๋ฉด ์ค๋ฅ๋ฅผ ์์ฃผ ์ ํ๊ฒ ๋๋ค. (error: cannot convert value of type 'String.Element' (aka 'Character') to closure result type 'String) '์ด๊ฒ ์ ์๋จ? ใ ใ ' ๋ผ๋ ์๊ฐ์ด ๋ค ์ ๋๋ก ์๋๋ค. ์๋ฌดํผ ์ด๋ฐ ์ค๋ฅ๋ฅผ ์์ฃผ ์ ํ๊ธฐ์ ๊ธ๋ก ์ ๋ฆฌํ๋ฉด์ ๋ค์ ํ ๋ฒ ๋ณต์ตํ๋ ค๊ณ ํ๋ค. 1. ๋ฌธ์์ด ํ ๋ณํํ๊ธฐ 1. String -> Int ๋ค๋ฅธ ์ธ์ด์์์ฒ๋ผ Int()๋ก ํ ๋ณํ์ ์งํํ๋ค. ์ด ๋, String์ธ์ง SubString์ธ์ง Character์ธ์ง ์ ์ดํด๋ณธ๋ค. (๊ทธ๋ ์ง ์์ผ๋ฉด... error: cannot convert value of type 'String.Element' (aka 'Chara..
[iOS / SwiftUI] ๋ค์ํ ์ํ ํ๋กํผํฐ๋ค์ ์์๋ณด์!
State์ Binding ์ง๋ ์๊ฐ @State์ @Binding ํ๋กํผํฐ ๋ํผ์ ๋ํด ํ์ตํ๋ค. 1. @State @State ํ๋กํผํฐ ๋ํผ๋ฅผ ์ฌ์ฉํด์ ์ํ ํ๋กํผํฐ๋ฅผ ์์ฑํ๋ฉด ํด๋น ํ๋กํผํฐ๊ฐ ์ ์ธ๋ ๋ทฐ์ ๋ฐ์ธ๋ฉํ ์ ์๊ฒ ๋๋ค. ์ข ๋ ์ฝ๊ฒ ์ค๋ช ํ์๋ฉด ๋ทฐ์ ๋ฐ์ธ๋ฉ์ด ๋์ด ์๋ ์ํํ๋กํผํฐ์ ๋ณ๊ฒฝ์ด ์ผ์ด๋๋ฉด ์๋์ผ๋ก ๋ทฐ๊ฐ ๊ฐฑ์ ๋๋ค๋ ๋ง์ด๋ค. ์ฝ๋๋ก ์ง์ ์ดํด๋ณด์. ์๋ ์ฝ๋๋ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ซ์๊ฐ 1์ฉ ์ฆ๊ฐํ๋๋ก ๊ตฌํํ ์ฑ์ด๋ค. struct ContentView: View { @State private var number: Int = 0 var body: some View { VStack { Text("\(self.number)") Button(action: { self.number += 1 }) ..
[iOS / SwiftUI] ํค๋ณด๋๊ฐ ์ฌ๋ผ์ง์ง ์์์...๐ฉ
SwiftUI Keyboard Dismiss ์ด์ ๊ตฌํํ ํ ๊ณผ์ ๋ฅผ ๋ค์ ํ ๋ฒ ๊ตฌํํ๋ ๋์ค์ ์ถ๊ฐํด๋ณด๊ณ ์ถ์ ๊ธฐ๋ฅ์ด ์์๋ค. ์ฌ์ฉ์ ์ ๋ ฅ์ ์ํํธ ํค๋ณด๋ ํน์ ๋ฒํผ์ ํตํด์ ์ ๋ ฅ ๋ฐ๋๋ฐ, ์ํํธ ํค๋ณด๋๋ก ์ ๋ ฅ ๋ฐ์ ๊ฒฝ์ฐ์ Submit์ ๋๋ฅด์ง ์๊ณ , ๋ทฐ์ ํด๋ฆญํ๋๋ผ๋ ์ํํธ ํค๋ณด๋๊ฐ ๋ซํ๋๋ก ๊ตฌํํ๊ณ ์ถ์๋ค. 1. Focused ์ฐ์ ์ด ๊ธฐ๋ฅ์ SwiftUI 3.0 (iOS 15) ์ด์๋ถํฐ ์ง์ํ๋ค. ๊ทธ๋ฐ ํ์ธ๊ฐ ์ ๋ง ๊ฐ๋จํ๊ฒ ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค. var body: some View { @State private var input: String = "" @FocusState private var isFocused: Bool // ์๋ต... VStack { TextField("PlaceHolder", $i..
[iOS / SwiftUI] ForEach๋ก View๋ฅผ ๋ฆฌํํ ๋ง ํด๋ณผ๊น์?
Swift UI์์ ForEach๋ก View ์ฌ๋ฌ ๊ฐ ์ค๋ ์คํฐ๋์์ ๋ ์จ๋ฅผ ๋ณด์ฌ์ฃผ๋ ํ์ด์ง๋ฅผ Swift UI๋ก ๊ตฌํํ๋ ๊ณผ์ ๋ฅผ ์งํํ๋ค. HStack๊ณผ VStack์ ํ์ฉํด์ ๊ตฌํํ๋ ๊ณผ์ ์๊ณ ๊ตฌํ ๊ฒฐ๊ณผ๋ ์๋์ ๊ฐ๋ค. ํ์ง๋ง ๊ตฌํ์ ์๋ฃํ๊ณ ๋ณด๋ ๋๋ถ๋ถ์ด ํ๋ ์ฝ๋ฉ๋์ด ์์ด์ ๊ฒน์น๋ ์ฝ๋๋ค์ด ๋ง์ ์ด๋ฅผ ์์ ํด์ฃผ๋ ์์ ์ ์งํํ๋ค. ์๋ ์ฌ์ง์ ๋ณด๋ฉด ๋นจ๊ฐ์ ๋ทฐ ์์ ์ด๋ก์ ๋ทฐ๋ค์ด ๊ฐ์ ํํ๋ก ๋ฐฐ์น๋์ด ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค. ๊ธฐ์กด์๋ HStack ๋ด๋ถ์ VStack์ ์ฌ๋ฌ ๊ฐ ๋ฐฐ์นํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ๋๋ฐ, ์ด๋ฅผ ForEach๋ฅผ ํ์ฉํด์ VStack์ ์ฌ์ฌ์ฉํ๋ ๋ฐฉ์์ผ๋ก ์์ ํ๋ค. 1. ๊ธฐ์กด ์ฝ๋ struct DailyHourWeatherView: View { var body: some View { HS..
[iOS / Swift] lim ํด๋ก์ -> 0 (ํด๋ก์ , ๊ทนํ์ผ๋ก ์ค์ฌ๋ณด๊ธฐ)
์ง๋ ์๊ฐ์ ๊ฐ์ธ์ ์ผ๋ก ํด๋ก์ ์ ๋ํด์ ์ข ๋ ์์๋ดค๋๋ฐ ์ค๋ ๊ฐ์์์๋ ํด๋ก์ ์ ๋ํ ์ง๋๋ฅผ ๋๊ฐ๋ค. ๋ณต์ต ์ฐจ์์์ ๊ฐ์๋ฅผ ๋ค์ผ๋ฉด์ ๋ค์ ํ ๋ฒ ์ ๋ฆฌํด๋ดค๋ค. ํด๋ก์ ํด๋ก์ ๋ ๊ธฐ๋ฅ์ ๊ฐ๊ณ ์๋ ์ฝ๋ ๋ธ๋ก์ด๋ค. ํด๋ก์ ์์๋ ์์์ ๋ณ์์ ๋ํ ์ฐธ์กฐ๋ฅผ ์บก์ณํ๊ณ ์ ์ฅํ ์ ์์ผ๋ฉฐ ํฌ๊ฒ 3๊ฐ์ง๋ก ๊ตฌ๋ถํ๋ค. ์ ์ญ ํจ์ ์ค์ฒฉ ํจ์ ํด๋ก์ ํํ์ 1. ์ ์ญ ํจ์ ์ฒซ ๋ฒ์งธ๋ก ์ ์ญํจ์๋ ์ฐ๋ฆฌ๊ฐ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ฉด์ ์ ์ํ๊ณ ํธ์ถํ๋ ํจ์๋ค์ด๋ค. func ํค์๋๋ฅผ ํตํด ์ ์ํ๋ค. ์ ์ญํจ์๋ ์ด๋ฆ์ ๊ฐ์ง๊ณ ์๊ณ ์ด๋ ํ ๊ฐ๋ ์บก์ณํ์ง ์๋ ํด๋ก์ ์ด๋ค. func justFunction() -> String { return "KODO" } 2. ์ค์ฒฉ ํจ์ ๋ ๋ฒ์งธ๋ก ์ค์ฒฉ ํจ์๋ ์ด๋ฆ์ ๊ฐ์ง๊ณ ๋๋ฌ์ผ ํจ์๋ก๋ถํฐ ๊ฐ์ ์บก์ณํ ์ ์๋..