
SwiftUI๋ ์ ์ธ์ UI ํ๋ ์์ํฌ๋ก, ๋ทฐ ์์ฒด๊ฐ State์ ๋ฐ์ํ์ฌ UI๋ฅผ ๊ฐฑ์ ํ๋ค. UIKit๊ณผ๋ ๋ฌ๋ฆฌ ViewController๊ฐ ์๊ณ , State๋ฅผ ์ค์ฌ์ผ๋ก UI๊ฐ ์ ๋ฐ์ดํธ ๋๊ธฐ ๋๋ฌธ์ ๋ช ์์ LifeCycle Method๊ฐ ์กด์ฌํ์ง ์๋๋ค. ๋๋ฌธ์ LifeCycle hook ๋์ ‘Modifier’๋ฅผ ์ ๊ณตํ๋๋ฐ ์ด๋ง์ ๋ UIKit์ฒ๋ผ ์์ธํ๊ฒ ๋๋์ง๋ ์๊ณ onAppear, onDisappear๋ก ์ข ๋ฅ๊ฐ ํ์ ์ ์ด๋ค.
State๊ฐ ๋ณํ๋ฉด ์ด๋ฅผ ๊ฐ์งํด View ์ ์ฒด๋ฅผ re-renderํ๊ฒ ๋๋๋ฐ, ์ด๋ ๋ฉ๋ชจ๋ฆฌ์์ View๋ ๊ฐ ํ์ ์ผ๋ก ๋ณ๊ฒฝ์ ์ด ์๋ ๋ถ๋ถ๋ง ์ฌ๊ตฌ์ฑ๋๋ค. ๋น๋๊ธฐ ์์ ์ญ์ UIKit์ callback, delegate, notification ๋ฑ์ ํ์ฉํ์ง๋ง SwiftUI๋ Combine, async/await๊ณผ ์์ฐ์ค๋ฌ์ด ์ฐ๊ณ๊ฐ ๊ฐ๋ฅํ๋ค.
SwiftUI Life Cycle ์์ธ ํ๋ฆ
- ์ฑ ์คํ → @main App Struct์ body ๋ด Scene ๊ตฌ์ฑ์ด ์คํ
- ๋ทฐ๊ฐ ํ๋ฉด์ ํ์๋ ๋ onAppear modifier ์คํ
- ์ํ ๋ณํ๊ฐ ๊ฐ์ง๋๋ฉด ๋ทฐ ์ ์ฒด๊ฐ ๋ค์ ๊ณ์ฐ๋๊ณ ํ๋ฉด ๊ฐฑ์
- ๋ทฐ๊ฐ ์ฌ๋ผ์ง ๋ onDisappear ์คํ
๋น๋๊ธฐ ์ด๋ฒคํธ ๊ด๋ฆฌ
SwiftUI๋ State ๋ณํ๋ฅผ ์ค์ฌ์ผ๋ก UI๋ฅผ ์ค๊ณํ๊ธฐ ๋๋ฌธ์ ๋น๋๊ธฐ ์์ ๊ฒฐ๊ณผ๋ฅผ State์ ๋ฐ์ํ๋ฉด ๊ณง๋ฐ๋ก ํ๋ฉด์ ๋ฐ์ํ ์ ์๋ค.
Combine
ํนํ Combine์ Publisher - Subscriber ๋ชจ๋ธ์ ์ด์ฉํด ๋น๋๊ธฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ๊ณ , ์ด๋ฅผ ์ฝ๊ฒ UI ์ํ์ ์ฐ๊ฒฐํ ์ ์๋ค.
import SwiftUI
import Combine
class ViewModel: ObservableObject {
@Published var text = "Loading..."
private var cancellables = Set<AnyCancellable>()
func loadData() {
fetchDataPublisher()
.receive(on: DispatchQueue.main)
.sink { completion in
if case .failure(let error) = completion {
self.text = "Error: \\(error.localizedDescription)"
}
} receiveValue: { value in
self.text = value
}
.store(in: &cancellables)
}
func fetchDataPublisher() -> AnyPublisher<String, Error> {
Just("Hello from Combine!")
.delay(for: .seconds(2), scheduler: DispatchQueue.global())
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
}
struct CombineView: View {
@StateObject private var vm = ViewModel()
var body: some View {
Text(vm.text)
.onAppear {
vm.loadData()
}
}
}
async / await
๋ํ SwiftUI๋ async-await ๋ฌธ๋ฒ์ ์ง์ View์์ task modifier์ ํจ๊ป ์ฌ์ฉํ ์ ์์ด, ๋น๋๊ธฐ ์ฝ๋๋ฅผ ๊น๋ํ๊ณ ๊ฐ๊ฒฐํ๊ฒ ์์ฑํ ์ ์๋ค. UIKit์์๋ ๋น๋๊ธฐ ์์ ์ดํ UI ์ ๋ฐ์ดํธ๋ฅผ ์ํด ์ด๋ฒคํธ๋ฅผ ๋ณ๋๋ก ๋ณด๋ด๋ ๋ฑ์ ๊ด๋ฆฌ๊ฐ ํ์ํ์ง๋ง SwiftUI๋ ์ํ ๋ฐ์ธ๋ฉ๋ง ํ๋ฉด ๋๋ค.
import SwiftUI
struct AsyncView: View {
@State private var text: String = "Loading..."
var body: some View {
Text(text)
.task {
await loadData()
}
}
func loadData() async {
do {
let result = try await fetchData()
text = result // ์ํ ๋ณ๊ฒฝ → UI ์๋ ๊ฐฑ์
} catch {
text = "Error: \\(error.localizedDescription)"
}
}
func fetchData() async throws -> String {
try await Task.sleep(nanoseconds: 2 * 1_000_000_000) // 2์ด ์ง์ฐ
return "Hello from async/await!"
}
}
๋ถ๋ช ํ์ฑ
๋ค๋ง SwiftUI๋ ๋ช ์์ LifeCycle์ ์ฌ์ฉํ์ง ์๊ธฐ์ rendering์ด ์นํ ํ๋ฉด์ด ๊ฐฑ์ ๋์ง ์๊ฑฐ๋, UI ์ ๋ฐ์ดํธ๊ฐ ๋์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ธฐ๋ ํ๋ค. ์ด๋ SwiftUI์์ State์ ๋ฐ๋ผ View๋ฅผ ์๋์ผ๋ก ๊ทธ๋ ค์ฃผ๊ธฐ์, ๋ด๋ถ์ ์ผ๋ก ์ธ์ ๋ทฐ๊ฐ ๋ค์ re-render ๋๋์ง, ์ด๋ค ์์ ์ View์ LifeCycle ์ด๋ฒคํธ๊ฐ ํธ์ถ๋๋์ง ๊ฐ๋ฐ์๊ฐ ์์ธกํ์ฌ ์ง์ ์ ์ดํ๊ธฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์ด๋ค. ์ฆ, UIKit๊ณผ๋ ๋ฌ๋ฆฌ SwiftUI๋ View์ LifeCycle ๊ด๋ฆฌ๊ฐ ๊ฐ์ ์ ์ด๊ณ ์ถ์ํ๋์ด ์๋ค.
๋ํ์ ์ธ ๋ฌธ์ ๋ค์ ์๋์ ๊ฐ๋ค.
1. State ๋ณ๊ฒฝ ๊ฐ์ง ์คํจ
SwiftUI๋ @State, @StateObject ๋ฑ์ State Property๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง ๋ทฐ๋ฅผ ๋ค์ ๊ทธ๋ฆฐ๋ค. (re-render) ๋๋ฌธ์ ์ํ๊ฐ ๋ณ๊ฒฝ๋์ง ์๊ฑฐ๋, ์ํ๊ฐ ๋ณ๊ฒฝ๋์ด๋ SwiftUI๊ฐ ์ด๋ฅผ ๊ฐ์งํ์ง ๋ชปํ๋ฉด ๋๋๋ง ๊ฐฑ์ ์ด ์ผ์ด๋์ง ์๋๋ฐ ์ํ๋ฅผ ์ง์ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ด๋ถ ํ๋กํผํฐ๋ง ์์ ํ๊ฑฐ๋, ์ฐธ์กฐ ํ์ ๋ด๋ถ ์์ฑ์ด ๋ณํ๋๋ฐ @Published๊ฐ ์ ๋๋ก ๋์ํ์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์ด๋ ๋ชจ๋ ์ํ๋ค์ด State Property๋ก ์ฌ๋ฐ๋ฅด๊ฒ ๊ด๋ฆฌ๋๊ณ ์๋์ง์ ๋ํ ํ์ธ์ด ํ์ํ๋ค.
2. View์ Identity ์ถฉ๋
SwiftUI๋ View๋ฅผ ๊ฐ ํ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ฉฐ, ๋ด๋ถ์ ์ผ๋ก View์ id๋ ๋ฐ์ดํฐ๊ฐ ๋ฐ๋์๋์ง ํ์ธํ์ฌ ์ด๋ฅผ ๋ค์ ๊ทธ๋ฆด์ง ๋ง์ง ๊ฒฐ์ ํ๋ค. id๊ฐ ์๊ฑฐ๋, ๋์ผํ id๊ฐ ์ฌ์ฌ์ฉ ๋ ๋, SwiftUI๊ฐ View๋ฅผ ๊ฐฑ์ ํ์ง ์๊ณ ๊ทธ๋๋ก ์ฌ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ List๋ ForEach์์ ๊ณ ์ ํ id๋ฅผ ์ง์ ํ์ง ์์ ๋๋ฝ์ด ์ผ์ด๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค. ์ด๋ ๋ณดํต id: \.self ๋ ๊ณ ์ ํ ์๋ณ์๋ฅผ ๋ช ์ํด์ฃผ๋ฉด ํด๊ฒฐ๋๋ค.
3. ๋น๋๊ธฐ ์์ ๊ณผ View State ๋ถ์ผ์น
๋น๋๊ธฐ ์์ ์ค์ View๊ฐ ์ฌ๋ผ์ก๋ค๊ฐ ๋ค์ ๋ํ๋๋ ๊ฒฝ์ฐ, ์ด์ ์์ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์๋์ง ์๊ฑฐ๋, ์์ ์๋ฃ ์์ ์ View๊ฐ ์ด๋ฏธ ๋ฉ๋ชจ๋ฆฌ์์ ์ฌ๋ผ์ง ๊ฒฝ์ฐ UI ์ ๋ฐ์ดํธ๊ฐ ๋ฌด์๋๋ ํ์์ด ์๊ธด๋ค. @State ๋ณ๊ฒฝ ์ View์ ์ ํจ์ฑ ํ์ธ์ด ํ์ํ๋ค.
4. View ์ฌ์ฌ์ฉ & ๋ฉ๋ชจ๋ฆฌ ์ต์ ํ
SwiftUI๋ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ํ์ ์๋ View๋ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ํ๊ฑฐ๋ ๋ค์ ์ฌ์ฉํ๋ค. ์ด๋ onAppear, onDisappear modifier๊ฐ ์์๊ณผ ๋ค๋ฅด๊ฒ ํธ์ถ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ด ๊ฐ๋ฐ์๊ฐ ์ง์ ์ ์ดํ๊ธฐ ์ด๋ ต๋ค. ์ด๋ ๊ฒ ๋๋ฉด View๊ฐ ์ฌ์์ฑ๋๊ฑฐ๋, ์ฌ์ฌ์ฉ๋๋ฉด์ ์์ํ์ง ๋ชปํ๊ฒ onAppear, onDisappear์ ๋ฃ์๋ ๋ก์ง์ด ์ฌ๋ฌ๋ฒ ํธ์ถ๋๊ฒ ๋๋ค. ๋๋ฌธ์ ํญ์ ์ํ๋ฅผ ์ถ์ ํด์ ์ค๋ณต ํธ์ถ์ ๋ฐฉ์งํด ์ฃผ์ด์ผ ํ๋ค.
'๐ iOS > ๐ถ ๊ถ๊ธ์ฆ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [iOS] ARC_๊ฐ์ฒด ์๋ช , weak์ unowned ์ฐจ์ด (0) | 2024.03.21 |
|---|---|
| [iOS] Swift์ ์ปดํ์ผ๋ฌ _ LLVM (1) | 2024.03.12 |
| [NSCache&URLCache]์ ์ด๋ฏธ์ง ํ์ผ์ด URLCache์์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋ ๋์คํฌ์ ์ ์ฅ๋ ๊น? (0) | 2024.01.28 |
| [UIKit]loadView์ view๋ ์ธ์ ํ ๋น๋ ๊น? (0) | 2024.01.27 |
| [Swift]super.init()์ด ๋ฐ๋์ ํ์ํ๋ ๊ฒฝ์ฐ (0) | 2023.11.08 |