[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-09 21:08:02 +09:00
parent f0befc887a
commit 93ec7e9056
363 changed files with 68333 additions and 64 deletions
@@ -0,0 +1,104 @@
---
id: ios-swiftui-lifecycle-view-identity
title: SwiftUI Lifecycle 와 View Identity
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [ios, swiftui, identity, lifecycle, vibe-coding]
tech_stack: { language: "Swift / SwiftUI", applicable_to: ["iOS 16+"] }
applied_in: []
aliases: [view identity, .id(), onAppear, onChange]
---
# SwiftUI Lifecycle 와 View Identity
> SwiftUI 는 view 를 **identity** 로 추적. identity 가 같으면 같은 view (state 보존), 다르면 새 view (state 리셋). `if/else` 분기, `.id()` modifier, `ForEach id`, 그리고 위치 — 이 4가지가 identity 를 결정.
## 📖 핵심 개념
- View 는 struct (value type) — render 마다 다시 만들어짐.
- 그러나 `@State` 는 identity 가 같으면 보존.
- identity 가 바뀌면 onAppear → onDisappear → 새 onAppear.
## 💻 코드 패턴
### `.id()` 로 강제 재생성
```swift
struct UserView: View {
let userId: String
@State private var draft = ""
var body: some View {
TextField("draft", text: $draft)
}
}
//
UserView(userId: id)
.id(id) // userId view draft
```
### if/else 가 identity 만듦
```swift
if isLoggedIn {
HomeView() // identity A
} else {
LoginView() // identity B
}
// onDisappear/onAppear
```
### ForEach 의 id 가 핵심
```swift
ForEach(items, id: \.id) { item in
Row(item: item)
}
// id row ( )
// index id reorder
```
### onAppear vs onChange vs task
```swift
struct Detail: View {
let id: String
@State private var data: Data?
var body: some View {
Text("...")
.onAppear { /* */ }
.task(id: id) {
// id task cancel + task. async .
self.data = try? await load(id: id)
}
.onChange(of: id) { oldId, newId in
// id
}
}
}
```
## 🤔 의사결정 기준
| 의도 | 도구 |
|---|---|
| 비동기 작업 + id 변경 시 cancel/restart | `.task(id:)` |
| 매 등장마다 1회 작업 | `.onAppear` |
| 특정 값 변경에 반응 | `.onChange(of:)` |
| sheet/navigation 등장만 | `.task` (lifecycle 묶임) |
| 강제 view 리셋 | `.id(value)` |
## ❌ 안티패턴
- **ForEach 에 `id: \.self` + 같은 값 가진 항목**: 충돌. unique id.
- **`.task` 에 cancellation 무시 + 긴 loop**: id 변경 후에도 옛 task 가 setState. 새 task 가 자동 cancel 하므로 within task에서 checkCancellation.
- **onAppear 에서 fetch 후 setState**: id 변경 시 cancel 안 됨. `.task(id:)` 권장.
- **`.id()` 남발**: 모든 view 강제 재생성 → 애니메이션 깨짐 + 성능 저하.
- **부모 rebuild 마다 자식 `@StateObject` 새로**: identity 다른 경우. 위치/조건 점검.
- **Animation 안에서 ForEach id 가 index**: 항목 추가/삭제 시 잘못된 row animate.
## 🤖 LLM 활용 힌트
- "이 view 는 어떤 값에 의해 identity 가 바뀌어야 하는가?" 질문 후 .id() 또는 .task(id:) 결정.
- 비동기 + cancel 필요 = `.task(id:)`.
## 🔗 관련 문서
- [[iOS_SwiftUI_State_Property_Wrappers]]
- [[iOS_Swift_Concurrency_async_await]]