๋ผ์ด๋ธ ์คํธ๋ฆฌ๋ฐ ์ฑ๋ฅ ๋ถ์ ๋ฐ ๊ฐ์ ๊ณผ์
- #iOS
- #SwiftUI
- #TCA
์๊ฐ
์๋ ํ์ธ์. ๋ ธ๋จธ์ค ๋ชจ๋ฐ์ผํ์์ iOS์ฑ ๊ฐ๋ฐ์ ๋งก๊ณ ์๋ ์ด๋์ฐ์ ๋๋ค.
fromm์ ๋ผ์ด๋ธ ์คํธ๋ฆฌ๋ฐ ์๋น์ค๊ฐ ์ ๋ฉด ์คํ๋์์ต๋๋ค!
์ด๋ฅผ ์ํด ๋ง์ ์ํฐ์คํธ, ํฌ๋ถ๋ค๊ป ๋ ์ข์ ๊ฒฝํ์ ์ ๊ณตํ๊ณ ์ ๋ผ์ด๋ธ ์คํธ๋ฆฌ๋ฐ ์ฑ๋ฅ์ ์ต์ ํํ๋ ์์ ์ ํ๊ฒ ๋์์ต๋๋ค.
Xcode Instruments๋ฅผ ํ์ฉํ ์ฑ๋ฅ ๋ถ์ ๊ณผ์ ๊ณผ, ์ด๋ป๊ฒ ์ฑ๋ฅ์ ๊ฐ์ ํ๋์ง์ ๋ํด ๊ณต์ ๋๋ฆฌ๊ฒ ์ต๋๋ค.
๋ผ์ด๋ธ ์ฑ๋ฅ ๋ถ์ ์กฐ๊ฑด
์ฑ๋ฅ์ ๋ถ์ํ๊ธฐ ์ํด ์ฌ์ฉ์์ ๋ค์ํ ํ๊ฒฝ์ ๊ณ ๋ คํ ํ์๊ฐ ์์์ต๋๋ค. ์ด๋ฅผ ์ํด ์ฌ๋ฌ ์กฐ๊ฑด์ ๊ฐ์ ํ์์ต๋๋ค.
1. ์ผ๋ฐ๊ธฐ๊ธฐ (iPhone 15 Plus)
2. ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ(iPhone 13 mini)
3. ์ ์ ๋ ฅ ๋ชจ๋
4. ํ ์ฑ์ด ๊ตฌ๋๋๊ณ ์๋ ํ๊ฒฝ
์กฐ๊ฑด๋ณ Instruments ๋ถ์
Xcode Instruments์ Time Profiler๋ฅผ ์ด์ฉํ์ฌ ํ์ ๋ถ์ํ์ต๋๋ค.
ํ์ ๋ฉ์ธ ์ค๋ ๋์ ์๋ต ์๋๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ๋ถ๋ฅ๋ฉ๋๋ค.
์๋ต ์๊ฐ | ์ค๋ช | ํ ๋ถ๋ฅ ๊ธฐ์ค |
---|---|---|
100ms ๋ฏธ๋ง | ์ผ๋ฐ์ ์ผ๋ก ์ฆ๊ฐ์ ์ธ ์๋๋ก ๋๊ปด์ง๋ ์ํ์ ๋๋ค. | - |
100ms ~ 250ms | ์ํฉ์ ๋ฐ๋ผ ์ด์ง ์ง์ฐ์ด ๋๊ปด์ง ์ ์๋ ์ํ์ ๋๋ค. | - |
250ms ์ด์ ~ 500ms ๋ฏธ๋ง | ๋๋ถ๋ถ์ ํด์์ โMicrohangโ์ผ๋ก ๊ฐ์ฃผํ๋ฉฐ, ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ํ๋จํ๋ ๊ธฐ์ค์ด ๋ฉ๋๋ค. | Microhang |
500ms ์ด์ | ์ฌ์ฉ์๊ฐ ๋๊น์ ๋๋ ์ ์๋ ์ํ๋ก, ์ ์ ํ(Full Hang)์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค. | ์ ์ ํ(Full Hang) |
[ํ ์คํธ 1] ์ผ๋ฐ๊ธฐ๊ธฐ (iPhone 15 Plus)
- ๋ง์ดํฌ๋กํ: 1๊ฐ
- ํ: 0๊ฐ
ํน๋ณํ ๋ฌธ์ ๊ฐ ๋ ๋งํ ํ์ ์กํ์ง ์์์ต๋๋ค.
[ํ ์คํธ 2] ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ + ๊ฒ์(3D)
- ๋ง์ดํฌ๋กํ 6๊ฐ
- ํ: 1๊ฐ
์ฝ๊ฐ ์ํฅ์ด ์๋ ๊ฒ์ผ๋ก ๋ณด์ด๋ ์ฌ๊ฐํ ์์ค์ ์๋๋๋ค.
[ํ ์คํธ 3] ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ + ์ ์ ๋ ฅ ๋ชจ๋
- ๋ง์ดํฌ๋กํ: 36๊ฐ
- ํ: 2๊ฐ
ํ์ด ๊ธ๊ฒฉํ ์ฆ๊ฐํ์ต๋๋ค.
[ํ ์คํธ 4] ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ + ์ ์ ๋ ฅ ๋ชจ๋ + ๊ฒ์ + ๋ นํ
- ๋ง์ดํฌ๋กํ: 46๊ฐ
- ํ: 2๊ฐ
ํ ์คํธ 3๊ณผ ๋น์ทํ ์์์ ๋ณด์์ต๋๋ค.
๋ถ์ ๊ฒฐ๊ณผ, ๊ฒ์/๋ นํ ๋ฑ ํ ์ฑ ๋์์ ์ํฅ๋ณด๋จ ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ + ์ ์ ๋ ฅ ๋ชจ๋ ์ํฅ์ด ํฌ๋ค๊ณ ํ๋จํ ์ ์์ต๋๋ค.
๊ฒฐ๊ณผ
ํ ์คํธ ์กฐ๊ฑด | [ํ ์คํธ 1] ์ผ๋ฐ๊ธฐ๊ธฐ (iPhone 15 Plus) | [ํ ์คํธ 2] ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ + ๊ฒ์(3D) | [ํ ์คํธ 3] ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ + ์ ์ ๋ ฅ ๋ชจ๋ | [ํ ์คํธ 4] ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ + ์ ์ ๋ ฅ ๋ชจ๋ + ๊ฒ์ + ๋ นํ |
---|---|---|---|---|
๋ง์ดํฌ๋ก ํ | 1๊ฐ | 6๊ฐ | 36๊ฐ | 46๊ฐ |
ํ | 0๊ฐ | 1๊ฐ | 2๊ฐ | 2๊ฐ |
์ผ๋ฐ ๊ธฐ๊ธฐ ํ๊ฒฝ์์๋ ๋ฌธ์ ๊ฐ ๋ ๋งํ ํ์ ๋ํ๋์ง ์์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ ์ฑ๋ฅ ๊ธฐ๊ธฐ, ํนํ ์ ์ ๋ ฅ ๋ชจ๋์์๋ ์ฌ์ฉ์ฑ์ ์ํฅ์ ์ค ๋งํผ์ ํ์ด ๋ํ๋ฌ์ต๋๋ค.
ํนํ ๋๊ฐ์ง ๊ฒฝ์ฐ๊ฐ ๋ฌธ์ ๊ฐ ๋ ๋ง ํ๋๋ฐ์.
๋ ๊ฐ์ 500ms ์ด์์ ํ๊ณผ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ํ๋๋ 500ms ์ดํ์ ๋ค์์ ๋ง์ดํฌ๋ก ํ ์ ๋๋ค.
ํ ๋ถ์
500ms ์ด์์ ํ ๋ถ์
๋ฌธ์ ๊ฐ ๋ ํ์ Instruments ํ์๋ผ์ธ์ ํ์ธํด๋ณด๋ฉด, ํด๋น ํ์ด ๋ํ๋๋ ์์ ์ ๋ฉ์ธ ์ค๋ ๋๊ฐ ํ๋ฐํ ๋์ํ๊ณ ์์์ ์ ์ ์์ต๋๋ค.
์ด ๊ฒฝ์ฐ์ ๋ฉ์ธ ์ค๋ ๋๊ฐ ๊ณผ๋ํ๊ฒ ๋ฐ๋น ์ ธ ์ฌ์ฉ์์ ์ก์ ์ ๋ฐ์ํ์ง ๋ชปํ๋ ์ํฉ์ด ๋ฐ์ํฉ๋๋ค.
ํ์ ๋ผ์ธ์ ์ธ ๋ฒ์งธ ์ค์ SwiftUI์ body์คํ์ ์ถ์ ํ๋ ํ์๋ผ์ธ์ ๋๋ค.
์ด๋ฅผ ํ์ธํด๋ณด๋ฉด LiveStreamingHostView์ body ์คํ ์๊ฐ์ด ๋ค๋ฅธ ๋ทฐ์ ๋นํด ํ์ ํ ๊ธธ๋ค๋ ์ ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ฅผ ๊ทผ๊ฑฐ๋ก LiveStreamingHostView์ ๋ ๋๋ง ์๊ฐ์ด ์ค๋ ๊ธธ์ด์ง๋ฉฐ ๋ฉ์ธ ์ค๋ ๋์ ๊ณผ๋ถํ๋ก ์ด์ด์ก๋ค๊ณ ํ๋จํ์ต๋๋ค.
500ms ์ดํ์ ๋ง์ดํฌ๋ก ํ ๋ถ์
ํ๋์ ๋ง์ดํฌ๋ก ํ์ ํ๋ํ์ฌ ๋ถ์ํ ๊ฒฐ๊ณผ์ ๋๋ค.
3๋ฒ์งธ ํ์๋ผ์ธ์์๋ LiveStreamingHostView๊ฐ ์ฌํ๊ฐ๋๋ ๋ชจ์ต์ ํ์ธํ ์ ์์ผ๋ฉฐ, ํ์๋ผ์ธ ๋ง์ง๋ง ์ค์์๋ ๋ฉ์ธ ์ค๋ ๋๊ฐ ํ๋ฐํ๊ฒ ๋์ํ๊ณ ์์์ ๋ณผ ์ ์์ต๋๋ค.
์ด๋ฅผ ํตํด, ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐ์ํ๋ ๋ง์ดํฌ๋ก ํ์ ์์ธ์ ์คํ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ LiveStreamingHostView๊ฐ ๋ฐ๋ณต์ ์ผ๋ก ์ฌํ๊ฐ๋๊ธฐ ๋๋ฌธ์ด๋ผ๋ ์ ์ ํ์ธํ ์ ์์์ต๋๋ค.
ํด๊ฒฐ ๋ฐฉํฅ ๊ฒฐ์
Instruments์ ํ์๋ผ์ธ ๋ถ์์ ํตํด LiveStreamingHostView์ ๋ฌธ์ ๊ฐ ์๋ค๋ ๊ฒ์ ์์๋์ต๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ๋ฐฉ์์ ๋ ๊ฐ์ง๋ก ๋๋ ์ ์์ต๋๋ค.
1. LiveStreamingHostView์ ์คํ ์๊ฐ์ ์ค์ธ๋ค.
2. LiveStreamingHostView์ ์ฌํ๊ฐ ํ์๋ฅผ ์ค์ธ๋ค.
๊ทธ๋ฌ๋ 1๋ฒ ํด๊ฒฐ์ฑ ์ ์นด๋ฉ๋ผ ํ๋ฉด ์ก์ถ๊ณผ ๊ฐ์ ๋ผ์ด๋ธ ์คํธ๋ฆฌ๋ฐ์ ํน์ฑ์ ๊ธฐ๋ฅ์ ์ถ์ํ๊ฑฐ๋ ์ต์ ํํ ์ ์๋ ๋ฐฉ๋ฒ์ ํ๊ณ๊ฐ ์์์ต๋๋ค.
๋ฐ๋ผ์ 2๋ฒ ํด๊ฒฐ์ฑ ์ ์ฑํํ์ฌ ๋ถํ์ํ ์ฌํ๊ฐ ํ์๋ฅผ ์ค์ด๋ ๋ฐฉํฅ์ผ๋ก ์ ๊ทผํ์ต๋๋ค.
๋ฌธ์ ๋ฐ์ ์์ธ
๋ทฐ์ ๋ถํ์ํ ์ฌํ๊ฐ๋ฅผ ์ค์ด๋ ค๋ฉด ๋ทฐ๋ฅผ ์ฌํ๊ฐํ๋ ์์ธ์ ์ฐพ์ ์ ๊ฑฐํด์ผ ํฉ๋๋ค.
์ด์ ๋ฐ๋ผ LiveStreamingHostView๊ฐ ์์ฃผ ์ฌํ๊ฐ๋๋ ์์ธ์ ํ์ ํ๊ธฐ ์ํด SwiftUI์ ._printChanges() ๋ฉ์๋๋ฅผ ํ์ฉํ์ต๋๋ค.
public var body: some View {
let _ = Self._printChanges()
ZStack {
// ...
[๊ฒฐ๊ณผ]
LiveStreamingHostView: @self, @identity, _viewStore, _keyboardResponder changed.
LiveStreamingHostView: \State.recorder changed. // ํ์ ๋ทฐ State
LiveStreamingHostView: @self, _viewStore changed.
LiveStreamingHostView: \State.recorder changed. // ํ์ ๋ทฐ State
LiveStreamingHostView: \ValueReference<LiveRecordState, InMemoryKey<LiveRecordState>>.<computed 0x00000001050f9174 (LiveRecordState)>, @self, _viewStore changed.
์ด๋ฅผ ํตํด ํ์ ๋ทฐ์์๋ง ์ํฅ์ ๋ฐ์์ผ ํ ์ํ ๋ณ๊ฒฝ์๋ ์์ ๋ทฐ๊ฐ ์ํฅ์ ๋ฐ๊ณ ์๋ค๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
์์ธ์ TCA์ Scope
fromm์ ๋ผ์ด๋ธ ์คํธ๋ฆฌ๋ฐ ํ์ด์ง๋ SwiftUI + TCA(The Composable Architecture)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
TCA๋ Point-Free์์ ๊ฐ๋ฐํ Swift ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์ํ ๊ด๋ฆฌ์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ชจ๋ํํ์ฌ ํ ์คํธ ๊ฐ๋ฅํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ํคํ ์ฒ๋ฅผ ์ ๊ณตํฉ๋๋ค.
์ ์ฒด ํ๋ฉด์ LiveStreamingHostView๋ผ๋ SwiftUI ๋ทฐ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ LiveStreamingHostView ๋ด๋ถ์ ํ์ ๋ทฐ๋ค์ด ์๊ณ LiveStreamingHostFeature์์ ๊ฐ ํ์๋ทฐ์ Reducer๋ค์ Scope๊ธฐ๋ฅ์ผ๋ก ์ฐ๊ฒฐํ๊ณ ์์ต๋๋ค.
ํ์ ๋ทฐ์ ์ํ ๋ณํ๊ฐ ์์ ๋ทฐ์ ์ํฅ์ ๋ฏธ์น๋ ์์ธ์ TCA์ Scope ์ฌ์ฉ ๋ฐฉ์์ ์์์ต๋๋ค.
Scope ๊ธฐ๋ฅ์ TCA์์ ๋งค์ฐ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ผ๋ก ์์ ๋ทฐ์ ํ์ ๋ทฐ ๊ฐ์ ์์ ๋ก์ด ์ํต์ ๊ฐ๋ฅํ๊ฒ ํด์ฃผ๋ ๋ฑ ์ฌ๋ฌ ์ฅ์ ์ ์ ๊ณตํฉ๋๋ค.
Scope ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ ค๋ฉด ํ์ ๋ทฐ์ State๋ฅผ ์์ ๋ทฐ์์ ์์ฑํด์ผ ํ๋๋ฐ ์ด ๊ณผ์ ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
fromm์์๋ ์๋์ ๊ฐ์ด scope ๊ธฐ๋ฅ์ ์ด์ฉํ๊ณ ์์ต๋๋ค.
public struct LiveStreamingHostViewReducer: Reducer {
// MARK: - State
@ObservableState
public struct State: Equatable {
// MARK: - Sub Reducer
public var chat: LiveChatViewReducer.State?
public var control: LiveStreamingControxlViewReducer.State
public var headerView: LiveStreamingHeaderViewReducer.State
public var liveRoomState: LiveRoomStatReducer.State?
public var recorder: LiveStreamingRecorderReducer.State
public var waitingRoom: LiveStreamingWaitingRoomReducer.State?
์ด๋ ํ์ ๋ทฐ์ State๊ฐ ์์ ๋ทฐ์ State์ ์ผ๋ถ๋ก ํฌํจ๋๋ฉด์, ํ์ ๋ทฐ์ ์ํ ๋ณ๊ฒฝ ์ฌํญ์ด ์์ ๋ทฐ๋ก ์ ํ๋๋ ํ์์ด ๋ํ๋ ๊ฒ์ ๋๋ค.
์ด๋ฌํ ๋์์ ํน์ ์ํฉ์์๋ ์ ์ฉํ ์ ์์ง๋ง, ํ์ฌ fromm์ ๋ผ์ด๋ธ ๊ธฐ๋ฅ์์๋ ๋ถํ์ํ ์ํ ๋ณ๊ฒฝ ์ ํ๋ฅผ ์ ๋ฐํ๋ฉฐ ์๋์น ์์ ๋์์ ์ด๋ํ๊ณ ์์์ต๋๋ค.
1. scope ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ์๊ธฐ
์ฒซ ๋ฒ์งธ ํด๊ฒฐ์ฑ ์ Scope๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ์๊ณ ๊ฐ ํ์ ๋ทฐ ์ปดํฌ๋ํธ์์ Reducer๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ ํ์ Reducer์์ ์์ ๋ฆฌ๋์๋ก action์ ์ ๋ฌํ ๊ฒฝ๋ก๋ ์์ด์ง๊ธฐ ๋๋ฌธ์ ๊ฐ ์ปดํฌ๋ํธ๋ค์ด ๋ฐ์ ํ๊ฒ action์ ์ฃผ๊ณ ๋ฐ์์ผํ๋ ํ์ฌ ์ํฉ์๋ ์ ํฉํ์ง ์์์ต๋๋ค.
2. scope ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉฐ ์ํ๋ฅผ ์ต์ ๋นํ์ง ์๋ ๋ฐฉ๋ฒ ์ฐพ๊ธฐ
Scope ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด์ ์ํ ๋ณ๊ฒฝ์ ์์๋ทฐ๋ก ์ ํํ์ง ์์ ๋ฐฉ๋ฒ์ ์ฐพ๋ ์ค TCA์์ ์ ๊ณตํ๋ ๋งคํฌ๋ก์์ ๋ฐฉ๋ฒ์ ์ฐพ์ ์ ์์์ต๋๋ค.
TCA์ @ObservableState
๋ ๊ฐ State ํ๋กํผํฐ์ @ObservationStateTracked
, @ObservationStateIgnored
๋ผ๋ ์ถ๊ฐ์ ์ธ ๋งคํฌ๋ก๋ฅผ ์์ฑํด์ฃผ๊ณ ์์ต๋๋ค.
์ด ๋งคํฌ๋ก๋ค์ ์ด๋ค ์ญํ ์ ํ๋์ง swift-composable-architecture์ ComposableArchitectureMacros ์์ค์ฝ๋์์ ํด๋น ๋งคํฌ๋ก์ ๊ตฌํ๋ถ๋ฅผ ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
@ObservationStateTracked
์ ๊ตฌํ๋ถ๋ฅผ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ค์ ์์ฑํ๋๋ก ๋์ด์๊ณ ,
public struct ObservationStateTrackedMacro: AccessorMacro {
public static func expansion<
Context: MacroExpansionContext,
Declaration: DeclSyntaxProtocol
>(
of node: AttributeSyntax,
providingAccessorsOf declaration: Declaration,
in context: Context
) throws -> [AccessorDeclSyntax] {
// ...
let initAccessor: AccessorDeclSyntax =
"""
@storageRestrictions(initializes: _\(identifier))
init(initialValue) {
_\(identifier) = initialValue
}
"""
let getAccessor: AccessorDeclSyntax =
"""
get {
\(raw: ObservableStateMacro.registrarVariableName).access(self, keyPath: \\.\(identifier))
return _\(identifier)
}
"""
let setAccessor: AccessorDeclSyntax =
"""
set {
\(raw: ObservableStateMacro.registrarVariableName).mutate(self, keyPath: \\.\(identifier), &_\(identifier), newValue, _$isIdentityEqual)
}
"""
let modifyAccessor: AccessorDeclSyntax = """
_modify {
let oldValue = _$observationRegistrar.willModify(self, keyPath: \\.\(identifier), &_\(identifier))
defer {
_$observationRegistrar.didModify(self, keyPath: \\.\(identifier), &_\(identifier), oldValue, _$isIdentityEqual)
}
yield &_\(identifier)
}
"""
return [initAccessor, getAccessor, setAccessor, modifyAccessor]
}
}
@ObservationStateIgnored
๋ ์ถ๊ฐ ์ฝ๋๋ฅผ ์์ฑํ์ง ์๋๋ก ๊ตฌํ๋์ด ์์ต๋๋ค.
public struct ObservationStateIgnoredMacro: AccessorMacro {
public static func expansion<
Context: MacroExpansionContext,
Declaration: DeclSyntaxProtocol
>(
of node: AttributeSyntax,
providingAccessorsOf declaration: Declaration,
in context: Context
) throws -> [AccessorDeclSyntax] {
return []
}
}
์ด๋ฆ์์ ์ ์ ์๋ฏ, ์ด ๋งคํฌ๋ก๋ค์ SwiftUI ์ ๋ฐ์ดํธ๋ฅผ ์ํด ์ํ๋ฅผ ์ต์ ๋นํ๋ ์ญํ ์ ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ @ObservationStateIgnored
๋ TCA ์ต์ ๋น ์์คํ
์ ์ํ๋ฅผ ๋ฑ๋กํ์ง ์์์ผ๋ก์จ ์ํ ๋ณํ์๋ SwiftUI์ body๊ฐ ์ฌํ๊ฐ๋์ง ์๋๋ก ํฉ๋๋ค.
@ObservableState
๋ ์ด๋ฏธ ๋งคํฌ๋ก๊ฐ ์ ์ฉ๋ ํ๋กํผํฐ์ ๋ํด ์ถ๊ฐ์ ์ธ ๋งคํฌ๋ก๋ฅผ ์์ฑํ์ง ์์ต๋๋ค.
๋ฐ๋ผ์ @ObservationStateIgnored
๋ฅผ ๋ช
์์ ์ผ๋ก ์ถ๊ฐํ๋ฉด @ObservationStateTracked
๊ฐ ์์ฑ๋์ง ์์ ํด๋น ํ๋กํผํฐ๊ฐ ์ต์ ๋น๋์ง ์๋๋ก ์ค์ ํ ์ ์์ต๋๋ค.
๊ฐ์
ํ์ฌ ์ํฉ์์๋ ์์ Reducer๊ฐ ํ์ Reducer์ State๋ฅผ ์ต์ ๋นํ ํ์๊ฐ ์๊ธฐ ๋๋ฌธ์ @ObservationStateIgnored
๋งคํฌ๋ก๋ฅผ ์ฌ์ฉํ์ฌ ์์๋ทฐ๊ฐ ํ์๋ทฐ์ State์ ์ํฅ์ ๋ฐ์ง ์๋๋ก ํ์ต๋๋ค.
public struct LiveStreamingHostReducer: Reducer {
@ObservableState
public struct State: Equatable {
// MARK: - Sub Reducers
@ObservationStateIgnored
public var chat: LiveChatReducer.State?
@ObservationStateIgnored
public var control: LiveStreamingControlReducer.State
@ObservationStateIgnored
public var headerView: LiveStreamingHeaderReducer.State
@ObservationStateIgnored
public var recorder: LiveStreamingRecorderFeature.State
// ...
๊ฒฐ๊ณผ
๊ฐ์ ์ ํตํด LiveStreamingHostView๊ฐ ํ์ ๋ทฐ ์ํ๋ก ์ธํด ์ฌํ๊ฐ๋๋ ํ์๋ฅผ ์ค์ผ ์ ์์์ต๋๋ค.
๋ํ ์์ ๋ทฐ์ ์ฌํ๊ฐ๊ฐ ํ์ ๋ทฐ์ ์ฌํ๊ฐ๋ก ์ด์ด์ง์ง ์๊ฒ ๋์ด, LiveStreamingHostView์ ํ๊ท body ์คํ ์๊ฐ์ด 167ms์์ 11ms๋ก 93.41% ๊ฐ์ํ์์ต๋๋ค.
๊ฐ์ ์
๊ฐ์ ํ
์ด์ ๋ฐ๋ผ ํ, ๋ง์ดํฌ๋ก ํ ๋ํ ๋์ ๋๊ฒ ์ค์ด๋ ๋ชจ์ต์ ๋๋ค.
๊ฐ์ ์
๊ฐ์ ํ
๋ง๋ฌด๋ฆฌ
@ObservationStateIgnored
๋งคํฌ๋ก๋ ์ด ์ธ์๋ ๋ค์ํ ํ์ฉ ๊ฐ๋ฅ์ฑ์ด ์์ ๊ฒ์ผ๋ก ๋ณด์
๋๋ค.
์๋ฅผ ๋ค๋ฉด struct๋ก ๊ตฌ์ฑ๋ Reducer ํน์ฑ์ State ์ธ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ฐฉ๋ฒ์ด ์ ํ์ ์ธ๋ฐ์,
์ด๋ด ๋ @ObservationStateIgnored
๋งคํฌ๋ก๋ฅผ ํ์ฉํ๋ฉด, ๋ทฐ ์ฑ๋ฅ์ ์ํฅ์ ์ฃผ์ง ์์ผ๋ฉด์ ์ถ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค!
์ด ๊ธ์ด TCA๋ฅผ ์ ์ฉ ์ค์ด์ ๊ฐ๋ฐ์๋ถ๋ค๊ป ์กฐ๊ธ์ด๋๋ง ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค ๐