Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 99f2e5b

Browse files
committed
Refactor lifecycle and subscription handling in scenes
Moved subscription logic for candles and mids to async onAppear/onDisappear methods in both PerpetualScene and PerpetualsScene. Updated ViewModels to subscribe/unsubscribe to all periods or mids on appearance/disappearance, and removed redundant or now-unnecessary code. This improves resource management and ensures subscriptions are properly handled with SwiftUI view lifecycle.
1 parent e067b40 commit 99f2e5b

7 files changed

Lines changed: 72 additions & 65 deletions

File tree

Features/Perpetuals/Sources/Scenes/PerpetualScene.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,12 @@ public struct PerpetualScene: View {
169169
.taskOnce {
170170
model.fetch()
171171
}
172+
.onAppear {
173+
Task { await model.onAppear() }
174+
}
175+
.onDisappear {
176+
Task { await model.onDisappear() }
177+
}
172178
.onChange(of: model.currentPeriod, initial: true, model.onPeriodChange)
173-
.onDisappear(perform: model.onDisappear)
174179
}
175180
}

Features/Perpetuals/Sources/Scenes/PerpetualsScene.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ public struct PerpetualsScene: View {
4444
await model.fetch()
4545
}
4646
}
47-
.onDisappear(perform: model.onDisappear)
47+
.onAppear {
48+
Task { await model.onAppear() }
49+
}
50+
.onDisappear {
51+
Task { await model.onDisappear() }
52+
}
4853
.refreshable {
4954
await model.fetch()
5055
}

Features/Perpetuals/Sources/Types/ChartBounds.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,11 @@ struct ChartBounds {
3434
}
3535

3636
var axisFractionLength: Int {
37-
switch axisStride {
38-
case _ where axisStride >= 1: 0
39-
case _ where axisStride >= 0.1: 1
40-
case _ where axisStride >= 0.01: 2
41-
case _ where axisStride >= 0.001: 3
42-
case _ where axisStride >= 0.0001: 4
37+
switch maxPrice {
38+
case _ where maxPrice >= 1000: 0
39+
case _ where maxPrice >= 0.01: 2
40+
case _ where maxPrice >= 0.001: 3
41+
case _ where maxPrice >= 0.0001: 4
4342
default: 5
4443
}
4544
}

Features/Perpetuals/Sources/ViewModels/PerpetualSceneViewModel.swift

Lines changed: 30 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,7 @@ public final class PerpetualSceneViewModel {
4141

4242
public var state: StateViewType<[ChartCandleStick]> = .loading
4343
public var currentPeriod: ChartPeriod = .day
44-
45-
private var chartTask: Task<Void, Never>?
44+
let periods: [ChartPeriod] = [.hour, .day, .week, .month, .year, .all]
4645

4746
public var isPresentingInfoSheet: InfoSheetType?
4847
public var isPresentingModifyAlert: Bool?
@@ -127,33 +126,25 @@ public extension PerpetualSceneViewModel {
127126
}
128127
}
129128

129+
func onAppear() async {
130+
await subscribeCandles()
131+
await observeCandles()
132+
}
133+
134+
func onDisappear() async {
135+
await unsubscribeCandles()
136+
}
137+
130138
func onPeriodChange(_ oldPeriod: ChartPeriod, _ newPeriod: ChartPeriod) {
131-
chartTask?.cancel()
132-
chartTask = Task {
139+
Task {
133140
do {
134141
try await fetchCandlesticks()
135-
guard !Task.isCancelled else { return }
136-
await subscribeCandle()
137-
if oldPeriod != newPeriod {
138-
await unsubscribeCandle(period: oldPeriod)
139-
}
140-
await observeCandles()
141142
} catch {
142-
if !Task.isCancelled {
143-
state = .error(error)
144-
}
143+
state = .error(error)
145144
}
146145
}
147146
}
148147

149-
func onDisappear() {
150-
chartTask?.cancel()
151-
chartTask = nil
152-
Task {
153-
await unsubscribeCandle(period: currentPeriod)
154-
}
155-
}
156-
157148
func onSelectFundingRateInfo() {
158149
isPresentingInfoSheet = .fundingRate
159150
}
@@ -272,15 +263,6 @@ public extension PerpetualSceneViewModel {
272263
// MARK: - Private
273264

274265
private extension PerpetualSceneViewModel {
275-
func unsubscribeCandle(period: ChartPeriod) async {
276-
do {
277-
let subscription = ChartSubscription(coin: perpetual.name, period: period)
278-
try await observerService.unsubscribeCandle(subscription: subscription)
279-
} catch {
280-
debugLog("Chart unsubscribe failed: \(error)")
281-
}
282-
}
283-
284266
func fetchCandlesticks() async throws {
285267
state = .loading
286268
let candlesticks = try await perpetualService.candlesticks(
@@ -290,16 +272,30 @@ private extension PerpetualSceneViewModel {
290272
state = .data(candlesticks)
291273
}
292274

293-
func subscribeCandle() async {
275+
func subscribeCandles() async {
294276
do {
295-
try await observerService.subscribeCandle(
296-
subscription: .init(coin: perpetual.name, period: currentPeriod)
297-
)
277+
for period in periods {
278+
try await observerService.subscribeCandle(
279+
subscription: ChartSubscription(coin: perpetual.name, period: period)
280+
)
281+
}
298282
} catch {
299283
debugLog("Chart subscription failed: \(error)")
300284
}
301285
}
302286

287+
func unsubscribeCandles() async {
288+
do {
289+
for period in periods {
290+
try await observerService.unsubscribeCandle(
291+
subscription: ChartSubscription(coin: perpetual.name, period: period)
292+
)
293+
}
294+
} catch {
295+
debugLog("Chart unsubscribe failed: \(error)")
296+
}
297+
}
298+
303299
func observeCandles() async {
304300
for await candle in await observerService.chartService.makeStream() {
305301
handleChartUpdate(candle)

Features/Perpetuals/Sources/ViewModels/PerpetualsSceneViewModel.swift

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -89,20 +89,39 @@ public final class PerpetualsSceneViewModel {
8989
balance: walletBalance
9090
)
9191
}
92+
93+
// MARK: - Private
94+
95+
private func subscribeAllMids() async {
96+
do {
97+
try await observerService.subscribeAllMids()
98+
} catch {
99+
debugLog("AllMids subscribe failed: \(error)")
100+
}
101+
}
102+
103+
private func unsubscribeAllMids() async {
104+
do {
105+
try await observerService.unsubscribeAllMids()
106+
} catch {
107+
debugLog("AllMids unsubscribe failed: \(error)")
108+
}
109+
}
92110
}
93111

94112
// MARK: - Businesss Logic
95113

96114
extension PerpetualsSceneViewModel {
97115
func fetch() async {
98116
await updateMarkets()
117+
}
118+
119+
func onAppear() async {
99120
await subscribeAllMids()
100121
}
101122

102-
func onDisappear() {
103-
Task {
104-
await unsubscribeAllMids()
105-
}
123+
func onDisappear() async {
124+
await unsubscribeAllMids()
106125
}
107126

108127
func updateMarkets() async {
@@ -175,22 +194,4 @@ extension PerpetualsSceneViewModel {
175194
func onSelectBalance() {
176195
isPresentingPortfolio = true
177196
}
178-
179-
// MARK: - AllMids
180-
181-
private func subscribeAllMids() async {
182-
do {
183-
try await observerService.subscribeAllMids()
184-
} catch {
185-
debugLog("AllMids subscribe failed: \(error)")
186-
}
187-
}
188-
189-
private func unsubscribeAllMids() async {
190-
do {
191-
try await observerService.unsubscribeAllMids()
192-
} catch {
193-
debugLog("AllMids unsubscribe failed: \(error)")
194-
}
195-
}
196197
}

Packages/FeatureServices/PerpetualService/TestKit/PerpetualService+TestKit.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import PerpetualService
44
import Preferences
5+
import PreferencesTestKit
56
import Primitives
67
import Store
78
import StoreTestKit

core

Submodule core updated from f2de594 to 5c85f33

0 commit comments

Comments
 (0)