2023.10 ๊ธฐ์ค SwiftUI์์ life cycle updates modifier๋ก ์ง์ ๋ ๊ฒ์ 4๊ฐ์ด๋ค. ์ฌ๊ธฐ์ ๋ง์ง๋ง task๋ task๋ง ๋ฐ๋ก ํ๋ฒ ํ๋ณด๊ธฐ๋ก ํ๊ณ onAppear, onDisappear, task ์์๋ด ์๋ค ๋ค ๋๋ฃจ์~
SwiftUI์์ ํ๋ฉด์ ์ ํํ๋ ๋ฐฉ๋ฒ์๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๋ค. UIKit์์ ViewController๋ฅผ ์ฌ์ฉํ์ ๋๋ ํ๋ฉด ์ ํ๋๋ View๋ฅผ ViewController๋ก ๋ช ํํ ๊ตฌ๋ถํ ์ ์๋ ๋จ์๊ฐ ์์์ง๋ง SwiftUI ์์๋ view๋ผ๋ ๋จ์๊ฐ ๋ช ํํ๊ฒ ๊ตฌ๋ถ๋์ด ์๊ธฐ ๋ณด๋ค๋ View๊ฐ View๋ฅผ ๊ฐ์ธ๊ณ ์๊ฑฐ๋ ๋ค๋ฅธ View์ ์ผ๋ถ๋ถ์ด ๋ ์๋ ์๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ๊ณ ๋ คํด์ ์์๋ด์ผ ํ๋ค.
์ฐ์ ๊ฐ modifire์ ๊ฐ๋จํ ์ดํด๋ณด๋ฉด
onAppear
func onAppear(perform action: (() -> Void)? = nil) -> some View
action ํ๋ผ๋ฏธํฐ๋ก ํด๋ก์ ๋ฅผ ์ ๋ฌํ๋ค. default ๊ฐ์ด nil์ด๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก action์ ์ ๋ฌํด ์ฃผ์ง ์์๋ ๋๋ค.(action์ nil๋ก ์ ๋ฌํ๋ onAppear()์ ์ฐ์์๊ฐ ๋ฐ๋ก ์๋๊ฑธ๊น?ใ ใ ใ )
ํน์ View์ ์ ํ์ ๋ฐ๋ผ ํธ์ถ๋๋ ์ ํํ ์์ ์ด ๋ค๋ฅด์ง๋ง ์ฒ์์ผ๋ก ๋ ๋๋ง ๋ ํ๋ ์์ด ๋ํ๋๊ธฐ ์ ์ ์ก์ ํด๋ก์ ๊ฐ ์๋ฃ๋๋ค๊ณ ํ๋ค.
ParentView์์ ChildView๋ก ์ด๋ํ์ ๋ ChildView๊ฐ ๋ํ๋๊ธฐ ์ ์ onAppear์ action ์ด ํธ์ถ๋๋๊ฑธ ํ์ธํ ์ ์๋ค.
onAppear๋ ๋ทฐ๊ฐ ํ๋ฉด์ ๋ํ๋๊ธฐ ์ด์ ์ action ํด๋ก์ ๋ฅผ ์คํํ๋ค ๋ผ๊ณ ์ ๋ฆฌํ๋ฉด ๋ ๊ฒ ๊ฐ๋ค.
onDisappear
func onDisappear(perform action: (() -> Void)? = nil) -> some View
onDisappear ๋ํ onAppear์ ๊ฐ์ด action ํ๋ผ๋ฏธํฐ๋ก ํด๋ก์ ๋ฅผ ์ ๋ฌํ๊ณ default๊ฐ์ nil์ด๋ค. onAppear์ ๋ค๋ฅด๊ฒ ํ๋ฉด์์ View๊ฐ ์ฌ๋ผ์ง๊ธฐ ์ ๊น์ง action ํด๋ก์ ๊ฐ ์คํ๋์ง ์๋๋ค.
ParentView์์ ChildView๋ก ์ด๋ํ ๋ค dismiss ์ํค๋ฉด ํ๋ฉด์์ ChildView๊ฐ ์ฌ๋ผ์ง๊ณ ๋ ๋ค onDiasappear์ action ํด๋ก์ ธ๊ฐ ํธ์ถ๋๋ค.
task
func task(
priority: TaskPriority = .userInitiated,
_ action: @escaping () async -> Void
) -> some View
task๋ onAppear, onDisappear ์๋ ๋ฌ๋ฆฌ priority๋ผ๋ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ฐ์ง๊ณ ์๊ณ , action ์ async๋ก ๋์ด ์๋ค. task ๊ด๋ จํด์ ๋ฐ๋ก ํ๋ฒ ๋ค๋ฃจ๊ธฐ๋ก ํ๊ณ life cycle ๋ถ๋ถ๋ง ์ดํด ๋ณด๋ฉด
A closure that SwiftUI calls as an asynchronous task before the view appears. SwiftUI will automatically cancel the task at some point after the view disappears before the action completes. |
view appears ์ด์ ์ async task๊ฐ ์คํ๋๋ค๊ณ ์ ํ ์์ด์ onAppear ์ด์ ์ ํธ์ถ๋๋ ์ค ์์๋๋ฐ ํ๋ฒ๋ onAppear ์ด์ ์ ํธ์ถ๋๊ฑฐ ๋ชป๋ดค์ (ํน์ appear์ ๊ฐ๋ ์ด onAppear์๋ ๋ค๋ฅธ๊ฑธ๊น ๋๋ฅต... ใ )
๋ทฐ๊ฐ ํ๋ฉด์ ๋ค ๋ํ๋๊ณ ๋ ๋ค์ task์ action์ด ์คํ๋๋ค. ๋๋์ฒด before the view appears ์ ์๋ฏธ๊ฐ ๋ญ๊น ๐ค
ํ ์คํธ๋ฅผ ์ํด ์์ฑํ ์ฝ๋์ ๊ตฌ์กฐ๋ฅผ ์ดํด๋ณด๋ฉด,
๊ฐ์ฅ ์์๋ทฐ๋ฅผ ContentView๋ผ ํ ๋, ContentView๋ NavigationStack์ผ๋ก ChildView ์ด๋์ด ๊ฐ๋ฅํ๊ณ , ZStack์ผ๋ก ContentView ์ ์ฒด๋ฅผ ๋ฎ์ ์ ์๋ ChildView๋ ์กด์ฌํ๋ค.
์ฆ NavigationStack์ผ๋ก ๋ฐ์ด ๋ฃ๋ ๋ทฐ๋ ํ๋ฉด์ ๊ฐ๋ ค์ก๋ค ๋ํ๋๋ ๋ทฐ๋ ์ฐจ์ด๊ฐ ์์๊น ์์๋ณด๋ ๊ฒ. ์๊ฐํด๋ณด๋ ํญ๋ฐ๋ ํด์ผ ํ๋ค.
body property & init
View ๊ตฌ์กฐ์ฒด๋ View ํ๋กํ ์ฝ์ ๋ฐ๋ฅด๊ธฐ ๋๋ฌธ์ ์ด๋ ์์ ์์ appear์ ๋ถ์ฌ์ค ์ ์์
@main
struct LifeCycleTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.task {
print("๐ฉ ContentView ์ด๋: task Modifier before onAppear ๐")
}
.onAppear {
print("๐ฉ ContentView ์ด๋: ContentView onAppear ๐ป")
}
.task {
print("๐ฉ ContentView ์ด๋: task Modifier after onAppear ๐")
}
}
}
}
์ต์์ ๋ทฐ๋ ContentView์ด๊ณ ์ด๋ ์์ ์์ onAppear์ task modifier์ ์ฌ์ฉํ ์ ์๋ค.
struct ContentView: View {
@State private var isChildViewShow: Bool = false
var body: some View {
let _ = print("ContentView ๋ฐ๋ํ๋กํผํฐ ")
NavigationStack {
let _ = print("NavigationStack ๋ฐ๋ํ๋กํผํฐ")
ZStack {
ParentView(isChildViewShow: $isChildViewShow)
if isChildViewShow {
ChildView(isSelfShow: $isChildViewShow)
}
} //: ZStack
}
.task {
print("๐งก ContentView task modifier before onAppear ๐")
}
.onAppear {
print("๐งก ContentView NavigationStack onAppear ๐ป")
}
.task {
print("๐งก ContentView task modifier after onAppear ๐")
}
.onDisappear {
print("๐งก ContentView disappear ๐ช")
}
}
}
ContentView์ body property ๋ด๋ถ์ ๊ฐ์ฅ ์ต์์ ๋ทฐ์ธ NavigationonStack์ Appear์
ContentView์ ์ด๋ ์์ ์ onAppear ์ค์ ์ด๋ค๊ฒ ๋จผ์ ํธ์ถ ๋ ๊น?
var body: some View {
let _ = print("ContentView ๋ฐ๋ํ๋กํผํฐ ")
}
์ฐ์ body ํ๋กํผํฐ ๋ด๋ถ์์ print๋ฌธ์ ์ฌ์ฉํด์ body๊ฐ ๊ทธ๋ ค์ง ๋ ์ฝ์์ ์ฐ์ด๋ณผ ์ ์๋ค.
ContentView ๋ฐ๋ํ๋กํผํฐ
NavigationStack ๋ฐ๋ํ๋กํผํฐ
VStack ๋ฐ๋ํ๋กํผํฐ
๐งก ContentView NavigationStack onAppear ๐ป
๐ฉ ContentView ์ด๋: ContentView onAppear ๐ป
์ฝ์์์ ํ์ธํ ์ ์๋ ๊ฒ์
body ํ๋กํผํฐ๊ฐ ๋จผ์ ๊ทธ๋ ค์ง๊ณ ๊ทธ ํ์ onAppear๊ฐ ํธ์ถ๋๋ค
๐งก ContentView NavigationStack onAppear ๐ป
๐ฉ ContentView ์ด๋: ContentView onAppear ๐ป
๊ทธ๋ฆฌ๊ณ ๋ณผ ๊ฒ์ด ๋ฐ๋ก ๊ฐ์ฅ ์๋ ๋ ์ค! ๋ณด๋ฉด ContentView์ ์ต์์ ๋ทฐ์ onAppear modifier๊ฐ ํธ์ถ๋๊ณ ๊ทธ ํ์ ์ด๋ ์์ ์ ๊ฑธ์ด๋ onAppear๊ฐ ํธ์ถ ๋๋ค. body ํ๋กํผํฐ ๋ด๋ถ์ ๊ฐ์ฅ ์ต์์ ๋ทฐ์ onAppear๊ฐ ํธ์ถ๋๊ณ ๊ทธ ํ์ ํด๋น body ํ๋กํผํฐ๊ฐ ํฌํจ๋ View struct์ ์ด๋ ์์ ์ ๊ฑธ์ด๋ onAppear๊ฐ ํธ์ถ๋๋ค. (๋ฌผ๋ก ์ด ๋ชจ๋ ๊ฑด ๊ณต์์ ์ธ ๋ด์ฉ์ด ์๋๊ธฐ ๋๋ฌธ์ ์ธ์ ๋ ์ง ๋ฐ๋ ์ ์๋ค๊ณ ์๊ฐํจ)
NavigationLink {
ChildView(isSelfShow: $isChildViewShow)
.onAppear {
print("ChildView ์ด๋: ChildView onAppear")
}
} label: {
Text("๐ผ go to ChildView with NavigationLink")
}
ContentView๊ฐ ์ฑ์ ์ต์์ ๋ทฐ๋ผ ํน์ํ ๊ฒฝ์ฐ๋ก ํธ์ถ๋ ๊ฑธ ์๋ ์์ผ๋ ํ ๊ฐ๋ ํ์ธํด ๋ณด๋ฉด,
ParentView ๋ด๋ถ์๋ NavigationLink๋ฅผ ์ด์ฉํด์ ChildView๋ก ์ด๋ํ๋ ์ฝ๋๊ฐ ์๋ค.
struct ChildView: View {
@Binding var isSelfShow: Bool
var body: some View {
let _ = print("์น ๋ ๋ฐ๋ํ๋กํผํฐ")
VStack {
// ์๋ต
}
.background(.yellow)
.onAppear {
print("๐ค ChildView onAppear ๐ป")
}
}
}
ChildView ๋ด๋ถ์๋ body ํ๋กํผํฐ์ ์ต์์ ๋ทฐ์ onAppear๋ฅผ ๊ฑธ์ด ๋์๋ค.
์น ๋ ๋ฐ๋ํ๋กํผํฐ
๐ค ChildView onAppear ๐ป
ChildView ์ด๋: ChildView onAppear
ChildView์ body property๊ฐ ๋จผ์ ๊ทธ๋ ค์ง๊ณ ๊ทธ ํ ChildView์ ์ต์์ ๋ทฐ์ onAppear๊ฐ ํธ์ถ๋๋ค. ๊ทธ ํ์ ChildView์ ์ด๋ ์์ ์ ๊ฑธ์ด๋ onAppear๊ฐ ํธ์ถ๋๋ค.
init Vs. onAppear
struct ParentView: View {
@Binding var isChildViewShow: Bool
init(isChildViewShow: Binding<Bool>) {
self._isChildViewShow = isChildViewShow
print("ParentView init!!!")
}
var body: some View {
VStack {
let _ = print("ParentView ๋ฐ๋ํ๋กํผํฐ ๐ช")
NavigationLink {
ChildView(isSelfShow: $isChildViewShow)
} label: {
Text("๐ผ go to ChildView with NavigationLink")
}
Button {
print("๐ผ go to ChildView with ZStack")
isChildViewShow = true
} label: {
Text("๐ผ go to ChildView with ZStack")
}
.buttonStyle(.borderedProminent)
}
.onAppear {
print("๐ ParentView onAppear ๐ป")
}
}
}
๋ชจ๋ View์๋ค๊ฐ init์ ๋ถ์ฌ๋์๋๋ฐ ParentView๋ง ํ์ธํด๋ด ์๋ค.
ParentView init!!!
ParentView ๋ฐ๋ํ๋กํผํฐ ๐ช
๐ ParentView onAppear ๐ป
์ฐ์ init์ด ๊ฐ์ฅ ๋จผ์ ์คํ๋๋ค. ๊ทธ ํ body property๊ฐ ๊ทธ๋ ค์ง๊ณ , body์ ์ต์์ ๋ทฐ์ onAppear๊ฐ ํธ์ถ๋๋ค.
๊ทธ ํ NavigationLink๋ฅผ ํตํด์ ChildView๋ก ์ด๋ํ ๋ค ๋ค์ Parent๋ก ๋์์ค๋ฉด init๊ณผ onAppear์ ์ฐจ์ด๋ฅผ ์ ์ ์๋ค.
๐ ParentView onAppear ๐ป
onAppear๋ ํธ์ถ๋์ง๋ง init์ ํธ์ถ๋์ง ์๋๋ค. init์ ๋ทฐ์ ์ด๊ธฐํ ์์ ์ ํ ๋ฒ ํธ์ถ๋๋ฉฐ onAppear๋ View๊ฐ ํ๋ฉด์ ๋ณด์ฌ์ง ๋ ํธ์ถ๋๋ค. NavigationStack์ ์ํด ํ๋ฉด์ ๋ํ๋๋ฉด onAppear๊ฐ ํธ์ถ๋๋ค.
์ฌ๊ธฐ์ SwiftUI ๋ฐฉ์ฌํ๋ฉด ์๋๋ค. View๊ฐ ํ๋ฉด์ ๋ํ๋ ๋ ๊ผญ ํธ์ถ๋๊ฒ ์ง ํ๊ณ onAppear์ ๋งก๊ฒจ ๋ฒ๋ฆฌ๋ ์๊ฐ ์์์น ๋ชปํ ๋์์ ๋นํฉํ ์ ์๋ค. NavigationStack์ด ์๋ ZStack์ ์ฌ์ฉํด์ ChildView๋ก ParentView๋ฅผ ์์ ํ ๊ฐ๋ฆฐ ๋ค ChildView๋ฅผ ํ๋ฉด์์ ์ ๊ฑฐํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
Button {
print("๐ผ go to ChildView with ZStack")
isChildViewShow = true
} label: {
Text("๐ผ go to ChildView with ZStack")
}
.buttonStyle(.borderedProminent)
ParentView์๋ ๋ฒํผ์ด ์๋๋ฐ ์ด ๋ฒํผ์ ๋๋ฅด๋ฉด ContentView์ Binding ๋ ๊ฐ์ธ isChildViewShow๊ฐ true๊ฐ ๋๋ค.
NavigationStack {
ZStack {
ParentView(isChildViewShow: $isChildViewShow)
if isChildViewShow {
ChildView(isSelfShow: $isChildViewShow)
}
} //: ZStack
}
ContentView์๋ isChildViewShow๊ฐ true๊ฐ ๋๋ฉด ZStack ์ ์ฒด๋ฅผ ๋ฎ๋ ChildView๊ฐ ํ๋ฉด์ ๋ํ๋๊ฒ ๋๋ค.
ParentView init!!!
ParentView ๋ฐ๋ํ๋กํผํฐ ๐ช
๐ ParentView onAppear ๐ป
-------- ChildView๋ก ์ด๋ --------
๐ผ go to ChildView with ZStack
ParentView init!!!
ChildView init!!!
ParentView ๋ฐ๋ํ๋กํผํฐ ๐ช
ChildView init!!!
์น ๋ ๋ฐ๋ํ๋กํผํฐ ๐ช
๐ค ChildView onAppear ๐ป
-------- ParentView ์ด๋ --------
ParentView init!!!
ParentView ๋ฐ๋ํ๋กํผํฐ ๐ช
ChildView init!!!
์น ๋ ๋ฐ๋ํ๋กํผํฐ ๐ช
NavigationStack์ด ์๋๋ผ ์ด๋ฏธ ๋ํ๋ ํ๋ฉด์ ์๋ก์ด ํ๋ฉด์ ๊ทธ๋ ค์ฃผ๊ธฐ ๋๋ฌธ์ onAppear๋ ํ ๋ฒ ํธ์ถ๋๊ณ , initializer๋ ํ๋ฉด์์ ๊ฐ๋ ค์ง ๋, ํ๋ฉด์ ๋ํ๋ ๋ ํธ์ถ๋๋ค. ์ ํํ ๋งํ๋ฉด dependency์ ์ํด body property๊ฐ ์๋ก ๊ทธ๋ ค์ง๊ธฐ ๋๋ฌธ์ธ๋ฐ
@State private var isChildViewShow: Bool = false
ContentView์ ์ ์๋ isChildViewShow์ ๊ฐ์ด ๋ฐ๋๋ฉด์ ContentView์ body ํ๋กํผํฐ๋ฅผ ์๋ก ๊ทธ๋ฆฌ๊ณ , ParentView, ChildView ๋ํ isChildViewShow State์ Bind ๋์ด ์์ด body ํ๋กํผํฐ๊ฐ ์ ๋ฐ์ดํธ ๋๋ค.
์ดํด๊ฐ ๋์ง ์๋๊ฑด, ParentView์ id๊ฐ ๊ฐ๊ธฐ ๋๋ฌธ์ init ๋ํ ํ๋ฒ๋ง ํธ์ถ๋ ๊ฒ์ผ๋ก ์์ํ๋๋ฐ body property๊ฐ ์ ๋ฐ์ดํธ ๋๋ฉด์ ์ด๋์ ๋ผ์ด์ ๋ ํจ๊ป ํธ์ถ๋์๋ค. (์ด์ ์๋ ์ฌ๋ ์๋์... ์ ๋ฐ)
task and onAppear
struct ContentView: View {
@State private var isChildViewShow: Bool = false
init() {
print("ContentView init!!!")
}
var body: some View {
let _ = print("ContentView ๋ฐ๋ํ๋กํผํฐ ๐ช")
NavigationStack {
ZStack {
ParentView(isChildViewShow: $isChildViewShow)
if isChildViewShow {
ChildView(isSelfShow: $isChildViewShow)
}
} //: ZStack
}
.task {
print("๐งก ContentView task modifier before onAppear ๐")
}
.onAppear {
print("๐งก ContentView NavigationStack onAppear ๐ป")
}
.task {
print("๐งก ContentView task modifier after onAppear ๐")
}
.onDisappear {
print("๐งก ContentView disappear ๐ช")
}
}
}
ContentView๋ง ๋๊ณ ๋น๊ตํด ๋ณด๋ฉด ์๋์ ๊ฐ์ ์์๋ก ํธ์ถ๋๋ค.
ContentView init!!!
ContentView ๋ฐ๋ํ๋กํผํฐ ๐ช
๐งก ContentView NavigationStack onAppear ๐ป
๐งก ContentView task modifier before onAppear ๐
๐งก ContentView task modifier after onAppear ๐
ContentView์ ์ด๋์ ๋ผ์ด์ ๊ฐ ํธ์ถ๋๊ณ ๋ฐ๋ํ๋กํผํฐ๊ฐ ๊ทธ๋ ค์ง๋ค. body ํ๋กํผํฐ์ ์ต์์ ๋ทฐ์๋ task1, onAppear, task2, onDisappear ์์ผ๋ก modifier๊ฐ ๋ถ์ด ์๋ค.
๊ฐ์ฅ ๋จผ์ ์ ์ ์๋ ๊ฒ์ modifier๊ฐ ๋ถ์ ์์ ์๊ด ์์ด onAppear๊ฐ ํธ์ถ๋ ๋ค task๊ฐ ํธ์ถ๋๋ค. ์ฌ๋ฌ task๊ฐ ๋ถ์ด ์์ ๋์๋ ๊ฐ์ฅ ์์ ์ ํ task๊ฐ ๋จผ์ ์คํ๋๊ณ , ๊ฐ์ฅ ๋์ค์ ๋ถ์ task๊ฐ ๋ง์ง๋ง์ผ๋ก ์คํ๋๋ค.
๊ณต์์ ์ธ ๋ด์ฉ์ ์๋๋ผ ์ด ์์๊ฐ ์ธ์ ๋ ๋ณํ ์ ์๊ฒ ์ง๋ง ์ฌ๋ฌ๋ฒ ์คํํด๋ onAppear๊ฐ ๋จผ์ ํธ์ถ๋๊ณ ์์์ ์๋ task ์์ผ๋ก ํธ์ถ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด์ ParentView๋ฅผ ํตํด ์ด๋ ์์ ๊ณผ body property ๋ด๋ถ modifier์ ๋น๊ตํด ๋ณด์
struct ContentView: View {
@State private var isChildViewShow: Bool = false
var body: some View {
NavigationStack {
ZStack {
ParentView(isChildViewShow: $isChildViewShow)
.task {
print("-> ๐ ParentView task before onAppear ๐")
}
.onAppear {
print("-> ๐ ParentView onAppear ๐ป")
}
.task {
print("-> ๐ ParentView task after onAppear ๐")
}
.onDisappear {
print("-> ๐ ParentView onDisappear ๐ช")
}
if isChildViewShow {
ChildView(isSelfShow: $isChildViewShow)
}
} //: ZStack
}
}
}
struct ParentView: View {
@Binding var isChildViewShow: Bool
init(isChildViewShow: Binding<Bool>) {
self._isChildViewShow = isChildViewShow
print("ParentView init!!!")
}
var body: some View {
let _ = print("ParentView ๋ฐ๋ํ๋กํผํฐ ๐ช")
VStack {
}
.task {
print("๐ ParentView task before onAppear ๐")
}
.onAppear {
print("๐ ParentView onAppear ๐ป")
}
.task {
print("๐ ParentView task after onAppear ๐")
}
.onDisappear {
print("๐ ParentView onDisappear ๐ช")
}
}
}
ParentView init!!!
ParentView ๋ฐ๋ํ๋กํผํฐ ๐ช
๐ ParentView onAppear ๐ป
-> ๐ ParentView onAppear ๐ป
๐ ParentView task before onAppear ๐
๐ ParentView task after onAppear ๐
-> ๐ ParentView task before onAppear ๐
-> ๐ ParentView task after onAppear ๐
์์๋ฅผ ๋ณด๋ฉด ์ด๋์์ ์ ๋ถ์ modifier๋ณด๋ค body ํ๋กํผํฐ์ ์ต์์ ๋ทฐ์์ ํธ์ถ๋ modifier๊ฐ ๋จผ์ ์คํ๋๋ค.
์ฐ์ ์์ ๐ฝ | ์ฐ์ ์์ ๐ผ |
ParentView(isChildViewShow: $isChildViewShow) .onAppear {} .task {} |
var body: some View { VStack {} .onAppear {} .task {} } |
init ์์ ๋ํ View์ด๊ธฐ ๋๋ฌธ์ View life cycle์ ์ฌ์ฉํ ์ ์๋ modifier์ ์ฌ์ฉํ ์ ์๋๋ฐ, body property ๋ด๋ถ์ ์ด๋ ์์ ๋ ๋ถ๋ถ์ ํผ์ฉํด์ ์ฐ๋ ๊ฒ ๋ณด๋ค ํ๋๋ฅผ ์ ํด ๋๊ณ ์ฌ์ฉํ๋๊ฒ ์ข์ ๋ฏ ํ๋ค.
๊ฐ์ธ์ ์ผ๋ก๋ ๋ฐ๋ ํ๋กํผํฐ์ ์ต์์ ๋ทฐ์์ onAppear๋ task๋ฅผ ํธ์ถํ๋๊ฒ ์ข๋ค๊ณ ์๊ฐํ๋ค. ์๋ํ๋ฉด ํด๋น ๋ทฐ์์ ์ฌ์ฉํ ๋น๋๊ธฐ ๋ก์ง์ด๋ appear ์ ํธ์ถ๋์ด์ผ ํ๋ ๋ก์ง์ View struct ๋ด๋ถ์์ ํจ๊ป ์ ์ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ง์ฝ ์ด๋ ์์ ์์ onAppear๋ task modifier์ ์ฌ์ฉํ๋ค๋ฉด ์ค๋ณต๋๋ ์ฝ๋๊ฐ ์๊ธฐ๊ฒ ๋๋ค. ์๋ฅผ ๋ค์ด์ ParentView๋ฅผ ํ๋์ ํ๋ฉด์์ ์ฌ์ฉํ๊ณ ์ด๋ ์์ ์์ onAppear์ task๋ฅผ ์ ์ํ๋ค๋ฉด ๋ค๋ฅธ ํ๋ฉด์์ ParentView๋ฅผ ์ฌ์ฉํ ๋ ๋ ๋ค์ onAppear์ task๋ฅผ ์ ์ํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
onDisappear
struct ParentView: View {
@Binding var isChildViewShow: Bool
var body: some View {
VStack {
NavigationLink {
ChildView(isSelfShow: $isChildViewShow)
} label: {
Text("๐ผ go to ChildView with NavigationLink")
}
Button {
print("๐ผ go to ChildView with ZStack")
isChildViewShow = true
} label: {
Text("๐ผ go to ChildView with ZStack")
}
.buttonStyle(.borderedProminent)
}
.onDisappear {
print("๐ ParentView onDisappear ๐ช")
}
}
}
struct ChildView: View {
@Binding var isSelfShow: Bool
var body: some View {
VStack {
Spacer()
Text("Child View")
.frame(maxWidth: .infinity)
Button {
isSelfShow = false
} label: {
Text("go to ContentView dismiss ZStack")
}
.buttonStyle(.borderedProminent)
Spacer()
}
.background(.yellow)
.onDisappear {
print("๐ค ChildView disappear ๐ช")
}
}
}
NavigationStack์ผ๋ก ChildView๋ฅผ ์์๋ค๊ฐ pop ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํธ์ถ๋๋ค.
ChildView ์ด๋: ChildView onAppear
๐ ParentView onDisappear ๐ช
๐ค ChildView disappear ๐ช
NavigationStack์ผ๋ก ChildView๊ฐ ๋ค์ด์ค๋ฉด ParentView๋ onDisappear ๋๋ค. ์ฆ NavigationStack์์ ํ๋ฉด์ ๋ณด์ด์ง ์๊ฒ ๋๋ฉด onDisappear๊ฐ ํธ์ถ๋๋ค.
ChildView ๋ํ NavigationStack์์ ์ ๊ฑฐ๋๋ฉด onDisappear๋ฅผ ํธ์ถํ๋ค.
onAppear modifier์ ์ฌ์ฉํ๋ฉด onDisappear์ ์์ ์ ๋ ๋ช ํํ ์ ์ ์๋ค.
๐ ParentView onAppear ๐ป
๐ค ChildView onAppear ๐ป
๐ ParentView onDisappear ๐ช
๐ ParentView onAppear ๐ป
๐ค ChildView disappear ๐ช
์ฒ์ ํ๋ฉด์ ParentView๊ฐ ๋ํ๋ ๋ onAppear๊ฐ ํธ์ถ๋๊ณ NavigationStack์ผ๋ก ChildView๋ก ์ด๋ํ๋ฉด ChildView์ onAppear๊ฐ ํธ์ถ๋ ๋ค ParentView๋ ํ๋ฉด์์ ๋ณด์ด์ง ์์ผ๋ฏ๋ก onDisappear๊ฐ ํธ์ถ๋๋ค. ๊ทธ ํ pop์ ํตํด ChildView๋ฅผ ํ๋ฉด์์ ์๋ณด์ด๊ฒ ํ๋ฉด ParentView์ onAppear๊ฐ ํธ์ถ๋๊ณ ChildView์ onDisappear๊ฐ ํธ์ถ๋๋ค.
NavigationStack {
ZStack {
ParentView(isChildViewShow: $isChildViewShow)
if isChildViewShow {
ChildView(isSelfShow: $isChildViewShow)
}
} //: ZStack
}
์ด์ ZStack์ ์ฌ์ฉํด์ ChildView๋ก ParentView๋ฅผ ์์ ํ ๊ฐ๋ฆฌ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
๐ ParentView onAppear ๐ป
๐ผ go to ChildView with ZStack
๐ค ChildView onAppear ๐ป
๐ค ChildView disappear ๐ช
ParentView๋ ์ด๋ฏธ ํ๋ฉด์ ๋ํ๋ ์ํ์ด๊ธฐ ๋๋ฌธ์ onAppear๋ ํ๋ฒ๋ง ํธ์ถ๋๋ค. ChildView๋ ํ๋ฉด์ ๋ํ๋๋ฉด onAppear ๋ฅผ ํธ์ถํ๊ณ ํ๋ฉด์์ ์ฌ๋ผ์ง๋ ์๊ฐ onDisappear๋ฅผ ํธ์ถํ๋ค. Navigation๊ณผ ํ๋ฉด์ ๋จ์ ํ์ ๋ฐ ์ ๊ฑฐํ ๋์ modifier ํธ์ถ์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ฃผ์ํด์ ์ฌ์ฉํด์ผ ํ๋ค.
๋์ด ์๋๋ค ์ด์ TabView๋ฅผ ํ ์คํธ ํด๋ณด์ ๐๐
TabView
struct TabBarTest: View {
var body: some View {
TabView {
FirstView()
.tabItem {
Image(systemName: "01.circle.fill")
Text("1")
}
SecondView()
.tabItem {
Image(systemName: "02.circle.fill")
Text("2")
}
ThirdView()
.tabItem {
Image(systemName: "03.circle.fill")
Text("3")
}
}
}
}
struct FirstView: View {
var body: some View {
Text("First")
.task {
print("1. before task")
}
.onAppear {
print("1. appear")
}
.task {
print("1. after task")
}
.onDisappear {
print("1. disappear")
}
}
}
๊ฐ ํญ์ ํด๋น ํ๋ ๋ทฐ์๋ task ๋๊ฐ์ appear, disappear modifier์ ํธ์ถํ๋๋ก ํด๋๋ค. ์์์ผ๋ก๋ 1, 2, 3 ๋ฒ์งธ ํญ์ ํด๋นํ๋ ๋ชจ๋ View์ appear๊ฐ ํธ์ถ๋ ๊ฒ ๊ฐ์๋๋ฐ ์๋๋ค!
1. appear
1. before task
1. after task
์ฐ์ ์ฒ์์ ํ๋ฉด์ ํญ๋ทฐ๊ฐ ๋ํ๋๋ฉด ์ฒซ ๋ฒ์งธ ํญ์ appear์ task๋ง ํธ์ถ๋๋ค.
2. appear
1. disappear
2. before task
2. after task
์ดํ 2๋ฒ ํญ์ ๋๋ฅด๋ฉด 2๋ฒ view์ appear๊ฐ ํธ์ถ๋๊ณ ์ฒซ ๋ฒ์งธ ํญ์ 1๋ฒ ๋ทฐ๋ disappear๋ฅผ ํธ์ถํ๋ค. ํ๋ฉด์ ๋ค๋ฅธ ๋ทฐ๊ฐ appear ๋๋ฉด -> ๊ธฐ์กด์ ๋ทฐ๊ฐ disappear ๋๋ ์์๋ ์์์ ํ์ธํ ๊ฒ๊ณผ ๋์ผํ๋ค. ์ดํ 2๋ฒ ์งธ ๋ทฐ์ task๊ฐ ์์๋๋ก ํธ์ถ๋๋ค.
3. appear
3. before task
3. after task
2. disappear
์ด๋ฒ์๋ 2๋ฒ ํญ์์ 3๋ฒ ํญ์ผ๋ก ์ด๋ํ ๋์ธ๋ฐ, 2๋ฒ ๋ทฐ์ disappear ๋ณด๋ค 3๋ฒ ๋ทฐ์ task๊ฐ ๋จผ์ ์คํ๋์๋ค. task์ ๋ค๋ฅธ ๋ทฐ์ ์ ์๋ disappear ๊ฐ์ ์์๋ ์ ํด์ง์ง ์๊ณ ๋๋คํ๊ฒ ํธ์ถ๋๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค.
1. appear
1. before task
1. after task
3. disappear
๋ค์ 3๋ฒ์์ 1๋ฒ ํญ์ผ๋ก ๋์์ค๋ฉด 1๋ฒ์ onAppear๊ฐ ํธ์ถ๋๊ณ ์ฌ๋ผ์ง 3๋ฒ ๋ทฐ๋ disappear๋ฅผ ํธ์ถํ๋ค.
TabView ๋ํ NavigationStack๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ํ๋ฉด์ ๋ํ๋๋ฉด onAppear๋ฅผ ํธ์ถํ๊ณ ํ๋ฉด์์ ์ฌ๋ผ์ง๋ฉด onDisappear๋ฅผ ํธ์ถํ๋ค. task ๋ํ ํ๋ฉด์ ๋ํ๋ ๋๋ง๋ค ํธ์ถํ๋ ๊ฑธ ์ ์ ์๋ค.
struct SecondView: View {
init() {
print("2. init")
}
var body: some View {
let _ = print("2. body property")
Text("Second")
.task {
print("2. before task")
}
.onAppear {
print("2. appear")
}
.task {
print("2. after task")
}
.onDisappear {
print("2. disappear")
}
}
}
์ด๋ฒ์๋ ๊ฐ ํญ์ ํด๋น๋๋ ๋ชจ๋ ๋ทฐ์ initializer๋ฅผ ์ถ๊ฐํ๊ณ ๋ก๊ทธ๋ฅผ ์ฐ์ด์ฃผ์๋ค. body property๊ฐ ๊ทธ๋ ค์ง๋ ์์ ์๋ ๋ก๊ทธ๋ฅผ ์ฐ์๋ค.
1. init
2. init
3. init
1. body property
1. appear
1. before task
1. after task
์์ํ๋ฐ๋ก init์ ๋ชจ๋ ํธ์ถ๋๋ ๊ฒ์ ์ ์ ์๋๋ฐ
struct TabBarTest: View {
var body: some View {
TabView {
FirstView()
.tabItem {
Image(systemName: "01.circle.fill")
Text("1")
}
SecondView()
.tabItem {
Image(systemName: "02.circle.fill")
Text("2")
}
ThirdView()
.tabItem {
Image(systemName: "03.circle.fill")
Text("3")
}
}
}
}
TabView๋ฅผ ๊ทธ๋ฆด ๋ init ๋๊ธฐ ๋๋ฌธ์ด๋ค. ๊ฐ ํญ์ ๋ทฐ๊ฐ ํ๋ฉด์ ๋ํ๋ ๋ ๋น๋๊ธฐ ์ฝ๋๋ฅผ ์คํํด์ผ ํ๋ค๋ฉด init์ด ์๋๋ผ task๊ฐ ์ ๋นํ๋ค (์ฌ์ค ๊ทธ๋ฌ๋ผ๊ณ ์ ํ์ด ๋ง๋ค์ด ๋ modifier์ด๊ธฐ๋ ํ๋ค)
1. init
2. init
3. init
1. body property
1. appear
1. before task
1. after task
๋ค์ ์ดํด๋ณด๋ฉด appear ๋๊ธฐ ์ด์ ์ 1๋ฒ ๋ทฐ์ body๋ฅผ ๊ทธ๋ฆฐ๋ค. 1๋ฒ ํญ์์ 2๋ฒ ํญ์ผ๋ก ์ด๋ํ๋ฉด
2. body property
2. appear
1. disappear
2. before task
2. after task
2๋ฒ ๋ํ body property๋ฅผ ๊ทธ๋ฆฌ๊ณ appear๊ฐ ํธ์ถ๋๋ค. ์ฌ๊ธฐ์ ๋ค์ 1๋ฒ ํญ์ ๋๋ฅด๋ฉด
1. appear
2. disappear
1. before task
1. after task
1๋ฒ์ body property ๊ฐ ํธ์ถ๋์ง ์๋๋ค. ๊ทธ ์ด์ ๋ TabView์์ ์ง์ ํด ์ค ๊ฐ ํญ์ ๋ทฐ๊ฐ ์ด๋ฏธ ์์์ ID๋ฅผ ๋ถ์ฌ ๋ฐ๊ณ , ์ ๋ฐ์ดํธ ๋๋ dependency๋ ์๊ธฐ ๋๋ฌธ์ body property๋ฅผ ์๋ก ๊ทธ๋ ค์ฃผ์ง ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ฆ ํญ์ ๋๋ฌ ๋ทฐ๋ฅผ ์ด๋ํ ๋ ๋ณด์ฌ์ง๋ ๋ทฐ๋ค์ ํ ๋ฒ ๊ทธ๋ ค์ง๊ณ ๊ทธ ๊ทธ๋ ค์ง ๋ทฐ๋ฅผ ๋ค์ ๋ณด์ฌ์ฃผ๊ณ ์๋ ๊ฒ์ด๋ค. (๋ง์ฝ 1๋ฒ ํญ์์ 2๋ฒ ํญ์ผ๋ก, ๋ค์ 1๋ฒ ํญ์ผ๋ก ๋์์จ๋ค๊ณ ํ์ ๋ ์ด์ ์ 1๋ฒ ๋ทฐ์ ์ง๊ธ์ 1๋ฒ ๋ทฐ๋ ๊ฐ์ ๋ทฐ์ด๋ค. SwiftUI์์ ๊ตฌ์กฐ์ ์ผ๋ก ๊ฐ์ ID๋ฅผ ๊ฐ์ง ๋ทฐ๋ก ์ธ์ํ๊ธฐ ๋๋ฌธ์ ์ด์ ๋ทฐ๋ฅผ ์ฆ์ ํ๊ดดํ๊ณ ์๋ก ๊ทธ๋ฆฌ๋ ๊ฒ์ด ์๋๋ผ, ์ด์ ๋ทฐ๋ฅผ ๋ค์ ๋ณด์ฌ์ฃผ๊ณ ์๋ ๊ฒ์ด๋ค)
+) TabView ์์ฒด์ ๊ฑธ์ด๋ onAppear, task, onDisappear ์ค onAppear์ task๋ ํ๋ฉด์ ๋ณด์ผ ๋ ๊ฐ๊ฐ ํ ๋ฒ ํธ์ถ๋๋ค.
custom tabbar๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค๋ฅธ ๋์์ ํ๊ฒ ์ง๋ง ์ด ์ ๋ ์ดํด๋ดค์ผ๋ฉด ์ถฉ๋ถํ ๊ฒ ๊ฐ๋ค.
์ฌ๊ธฐ์ ๋์ด ์๋๋ค! ํ๋ ๋ ๋จ์๋ค ์ด์ ์ง์ง ๋ง์ง๋ง!! ๐ช๐
modal
struct ModalTestView: View {
@State private var isShowModal = false
var body: some View {
VStack {
Button("๋ชจ๋ฌ") {
isShowModal.toggle()
}
}
.task {
print("๐ ParentView task before onAppear ๐")
}
.onAppear {
print("๐ ParentView onAppear ๐ป")
}
.task {
print("๐ ParentView task after onAppear ๐")
}
.onDisappear {
print("๐ ParentView onDisappear ๐ช")
}
.sheet(isPresented: $isShowModal) {
ModalChildView()
}
}
}
struct ModalChildView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
Button("dismiss ๋ฒํผ") {
dismiss()
}
}
.task {
print("๐ค ChildView task before onAppear ๐")
}
.onAppear {
print("๐ค ChildView onAppear ๐ป")
}
.task {
print("๐ค ChildView task after onAppear ๐")
}
.onDisappear {
print("๐ค ChildView disappear ๐ช")
}
}
}
๋ฒํผ ๋๋ฌ์ ModalChildView๋ฅผ ํ๋ฉด์ ๋์ฐ๋ฉด
๐ ParentView onAppear ๐ป
๐ ParentView task after onAppear ๐
๐ ParentView task before onAppear ๐
๐ค ChildView onAppear ๐ป
๐ค ChildView task before onAppear ๐
๐ค ChildView task after onAppear ๐
์ฒ์ ์ธ ์ค์ ์ฒ์ ์คํํ์ ๋ ParentView๊ฐ ํ๋ฉด์ ๋ณด์ด๋ ์๊ฐ ํธ์ถ๋๋ modifier์ด๋ค. ์ดํ ๋ฒํผ์ ๋๋ฌ ๋ชจ๋ฌ์ ๋์ฐ๋ฉด ์๋ ์ธ ์ค์ด ๋ฌ๋ค.
๐ค ChildView disappear ๐ช
์ดํ ๋ฒํผ์ ๋๋ฌ ๋ชจ๋ฌ์ ๋ซ์ผ๋ฉด childview์ onDisappear๋ง ํธ์ถ๋๊ณ , ParentView์ onAppear๋ ํธ์ถ๋์ง ์๋๋ค. ์ค์์ดํ ์ ์ค์ฒ๋ ๋ง์ฐฌ๊ฐ์ง!
1. sheet์ผ๋ก ๋ชจ๋ฌ์ ๋์ฐ๋ฉด ๋ชจ๋ฌ์ ๋์ด ParentView๋ onDisappear๊ฐ ํธ์ถ๋์ง ์๋๋ค.
2. sheet์ ๋ซ์๋ ParentView์ onAppear๋ ํธ์ถ๋์ง ์๋๋ค.
.fullScreenCover(isPresented: $isShowModal, content: {
ModalChildView()
})
.sheet modifier์ .fullScreenCover modifier๋ก ๋ฐ๊ฟ๋ ๋์์ ๋์ผํ๋ค.
.sheet(isPresented: $isShowModal) {
print("ParentView๋ก ๋์์ด")
} content: {
ModalChildView()
}
๋ง์ฝ ChildView์์ ParentView๋ก ๋์์์ ๋ ์คํํ ์ฝ๋๊ฐ ์๋ค๋ฉด onDismiss ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. sheet, fullScreenCover modifier ๋ชจ๋ ๊ฐ์ง๊ณ ์๋ ํ๋ผ๋ฏธํฐ์ด๋ค.
ParentView๋ก ๋์์ด
๐ค ChildView disappear ๐ช
ChildView์ onDisappear๊ฐ ํธ์ถ๋๊ธฐ ์ด์ ์ onDismiss๊ฐ ํธ์ถ๋๋ค.
.sheet(isPresented: $isShowModal, content: {
ModalChildView()
.presentationDetents([.medium])
})
ํน์ ์ ๋ฐ๋ง ๊ฐ๋ฆฌ๋ฉด ์ด๋ป๊ฒ ๋ ๊น ํ๋๋ฐ sheet, fullScreenCover์์ ๋์ํ ๊ฒ๊ณผ ๋์ผํ๊ฒ ๋์ํ๋ค.
๊ฒฐ๋ก
life cycle modifier | ํน์ง |
onAppear | - ๋ทฐ๊ฐ ํ๋ฉด์ ๋ํ๋๊ธฐ ์ด์ ์ ์คํ - NavigationStack : ํ๋ฉด์ ์ต์ด ๋ํ๋ ๋ ํธ์ถ, ChildView๊ฐ push๋๊ณ pop ๋ ๋ ํธ์ถ - ZStack : ์ฒ์ ํ๋ฉด์ ๋ํ๋ ๋ ํ๋ฒ๋ง ํธ์ถ, ChildView๊ฐ ํ๋ฉด์ ์ ์ฒด ๋ค ๊ฐ๋ ธ๋ค๊ฐ ์ฌ๋ผ์ ธ๋ onAppear๋ ํธ์ถ๋์ง ์์ -TabView: ํญ์ ๋๋ฌ ํ๋ฉด์์ ๋ํ๋ ๋ ๋ง๋ค - sheet: ๋ชจ๋ฌ๋ก ๋์์ก์ ๋ ํธ์ถ, ๋ชจ๋ฌ์ ๋์ฐ๋ View๋ผ๋ฉด modal์ ๋ซ์๋ ํธ์ถ๋์ง ์์ |
onDisappear | - ํ๋ฉด์์ View๊ฐ ์ฌ๋ผ์ง๊ณ ๋ ํ์ ์คํ - NavigationStack์์ ์ ๊ฑฐ๋ ๋ - TabView์์ ํญ์ ๋ฐ๊ฟ ํ๋ฉด์์ ์ฌ๋ผ์ง ๋ ๋ง๋ค - sheet: ๋ชจ๋ฌ๋ก ๋์์ก๋ค๊ฐ ์ฌ๋ผ์ง ๋, ๋ชจ๋ฌ์ ๋์ฐ๋ View๋ผ๋ฉด ๋ชจ๋ฌ์ ์ํด ํ๋ฉด์ ๊ฐ๋ ค์ ธ๋ ํธ์ถ๋์ง ์์ |
task | - ๋น๊ณต์์ ์ผ๋ก onAppear ๋ค์ ํธ์ถ๋จ - ์ฌ๋ฌ๊ฐ์ task๊ฐ ์๋ ๊ฒฝ์ฐ ์์์ ์๋ ์์ผ๋ก ์คํ |
init -> body property ๊ทธ๋ ค์ง -> onAppear ํธ์ถ
(init๊ณผ body property update์ ๊ฒฝ์ฐ depdency์ ์ํด ํธ์ถ๋ ์๋, ๋์ง ์์ ์๋ ์๊ธฐ ๋๋ฌธ์ ์ฃผ์)
์ด ์ ๋๋ฉด,,, ์ฌ์ฉํ ๋๋ง๋ค ์ฐ์ด๋ณด๋๊ฒ ๊ฐ์ฅ ๋ฒ ์คํธ์ด์ง ์์๊น ์ถ๊ธฐ๋ ํ๋ค ๋๋ฅต...๐ฅฒ
'iOS ๐ > SwiftUI' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[SwiftUI] Custom Toggle (0) | 2023.11.13 |
---|---|
[SwiftUI] Shape path๋ก Tooltip ๊ทธ๋ฆฌ๊ธฐ (0) | 2023.11.06 |
[SwiftUI] VStack ๊ณผ LazyVStack ๋ญ๊ฐ ๋ค๋ฅธ ๊ฑธ๊น? (1) | 2023.10.08 |
[SwiftUI] NavigationView (1) | 2023.09.22 |
[SwiftUI] ๊ฐ๋ก๋ชจ๋, ์ธ๋ก๋ชจ๋ ์ง์ํ๊ธฐ with @ViewBuilder (0) | 2023.09.20 |