์๋ ํ์ธ์~ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฌธ์ ์ ๋ํด ๋ ์์ธํ ์์๋ณผ๊ฒ์! ์ด๊ฑฐ ์ง์ง ์ค์ํ ๋ถ๋ถ์ธ๋ฐ ๋ง์ ๊ฐ๋ฐ์๋ค์ด ๋์น๋ ํจ์ ์ด์์ ใ ใ
Task์ ๋ฉ๋ชจ๋ฆฌ ๋์์ ๊ด๊ณ ๐ฆ
Task๋ ๋น๋๊ธฐ ์์ ์ ์์ํ๋ ๋ฐฉ๋ฒ์ธ๋ฐ, ๋ฌธ์ ๋ Task๊ฐ ๊ฐํ ์ฐธ์กฐ(strong reference)๋ฅผ ์์ฑํ๋ค๋ ์ ์ด์์. ๋ง์ฝ ํด๋ก์ ๋ด์์ self๋ฅผ ์บก์ฒํ๋ฉด ๋ทฐ๋ ๊ฐ์ฒด๊ฐ ์ฌ๋ผ์ ธ๋ Task๊ฐ ์๋ฃ๋ ๋๊น์ง ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๋์ง ์์ ์ ์์ด์!
func loadData() {
Task {
// ์ฌ๊ธฐ์ self๋ฅผ ๊ฐํ๊ฒ ์บก์ฒํจ
let data = await self.fetchSomething()
self.processData(data) // ๋ง์ฝ Task๊ฐ ์ค๋ ๊ฑธ๋ฆฌ๋๋ฐ ๊ฐ์ฒด๊ฐ ํด์ ๋์ด์ผ ํ๋ค๋ฉด?
}
}
์ด๋ ๊ฒ ๋๋ฉด ๋ทฐ๊ฐ ํ๋ฉด์์ ์ฌ๋ผ์ ธ๋ Task๊ฐ ๊ณ์ ์คํ๋๊ณ , ๊ทธ Task๊ฐ self๋ฅผ ๊ฐํ๊ฒ ์ฐธ์กฐํ๊ณ ์์ด์ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ๋์ง ์๋ ๋ฌธ์ ๊ฐ ์๊นใ ใ
ํด๊ฒฐ ๋ฐฉ๋ฒ 1: Task ์ทจ์ํ๊ธฐ ๐ช
์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ ๋ทฐ๋ ๊ฐ์ฒด๊ฐ ํด์ ๋ ๋ ๋ช ์์ ์ผ๋ก Task๋ฅผ ์ทจ์ํ๋ ๊ฑฐ์์.
class SomeViewModel {
private var dataTask: Task<Void, Never>?
func loadData() {
// ๊ธฐ์กด ์์
์ทจ์
dataTask?.cancel()
// ์ ์์
์์
dataTask = Task {
do {
let data = try await fetchSomething()
await MainActor.run {
self.processData(data)
}
} catch {
// ์๋ฌ ์ฒ๋ฆฌ
}
}
}
deinit {
// ๊ฐ์ฒด๊ฐ ํด์ ๋ ๋ ์์
์ทจ์
dataTask?.cancel()
}
}
SwiftUI์์๋ .onDisappear๋ .task ์์ ์๋ฅผ ํ์ฉํ ์ ์์ด์:
struct ContentView: View {
@State private var dataTask: Task<Void, Never>?
var body: some View {
Text("Hello")
.onAppear {
dataTask = Task {
// ๋น๋๊ธฐ ์์
}
}
.onDisappear {
// ๋ทฐ๊ฐ ์ฌ๋ผ์ง ๋ ์์
์ทจ์
dataTask?.cancel()
}
}
}
๋ ๊ฐ๋จํ๊ฒ๋ .task ์์ ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋ทฐ๊ฐ ์ฌ๋ผ์ง ๋ ์๋์ผ๋ก ์ทจ์ํด์ค์:
struct ContentView: View {
var body: some View {
Text("Hello")
.task {
// ์ด ์์
์ ๋ทฐ๊ฐ ์ฌ๋ผ์ง๋ฉด ์๋์ผ๋ก ์ทจ์๋จ
await fetchData()
}
}
}
ํด๊ฒฐ ๋ฐฉ๋ฒ 2: ์ฝํ ์ฐธ์กฐ ์ฌ์ฉํ๊ธฐ ๐ฑ
๋ค๋ฅธ ๋ฐฉ๋ฒ์ ํด๋ก์ ๋ด์์ self๋ฅผ ์ฝํ๊ฒ ์ฐธ์กฐํ๋ ๊ฑฐ์์:
func loadData() {
Task { [weak self] in
guard let self = self else { return }
// ๋๋
// guard let strongSelf = self else { return }
let data = await fetchSomething()
// self๊ฐ ์ด๋ฏธ ํด์ ๋์ผ๋ฉด ์ฌ๊ธฐ์ nil์ด ๋จ
await MainActor.run { [weak self] in
self?.processData(data)
}
}
}
ํด๊ฒฐ ๋ฐฉ๋ฒ 3: Task์ ๋น๋๊ธฐ ์ํ์ค ์กฐํฉํ๊ธฐ ๐ซ
iOS 15๋ถํฐ๋ AsyncSequence๋ฅผ ์ฌ์ฉํด ๋น๋๊ธฐ ์คํธ๋ฆผ์ ์ฒ๋ฆฌํ ์ ์๋๋ฐ, ์ด๊ฑธ ์ฌ์ฉํ๋ฉด ์์ ๊ด๋ฆฌ๊ฐ ๋ ์ฌ์์ ธ์:
class ViewModel {
private var cancellables: Set<AnyCancellable> = []
func startStreaming() {
let stream = AsyncStream<Data> { continuation in
// ์คํธ๋ฆผ ์ค์
// ์ข
๋ฃ ์ ํธ์ถํ ์ ์๋ onTermination ํธ๋ค๋ฌ ์ ๊ณต
}
Task {
for await data in stream {
// ๋ฐ์ดํฐ ์ฒ๋ฆฌ
}
}
}
deinit {
cancellables.forEach { $0.cancel() }
}
}
์ค์ ์ฑ์์ ์์ฃผ ๋ฐ์ํ๋ ๋ฉ๋ชจ๋ฆฌ ๋์ ์๋๋ฆฌ์ค ๐งจ
1. ๊ธด ๋ค์ด๋ก๋ ์์ :
func downloadLargeFile() {
Task {
let data = try await downloadFile() // ํ์ผ์ด ๋งค์ฐ ํฌ๋ฉด ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆผ
await MainActor.run {
self.fileData = data // ๋ค์ด๋ก๋ ์๋ฃ ์ ์ ๊ฐ์ฒด๊ฐ ํด์ ๋์ด์ผ ํ๋ค๋ฉด?
}
}
}
2. ๋ฌดํ ์คํธ๋ฆฌ๋ฐ:
func startLiveUpdates() {
Task {
while !Task.isCancelled {
let update = try await fetchUpdate()
await MainActor.run {
self.latestUpdate = update
}
try await Task.sleep(for: .seconds(1))
}
}
// Task๋ฅผ ์ ์ฅํ์ง ์๊ณ ์ทจ์ํ์ง ์์ผ๋ฉด?
}
3. SwiftUI ๋ทฐ์์ ํ์ด๋จธ ์ฌ์ฉ:
struct TimerView: View {
@State private var time = 0
var body: some View {
Text("Time: \(time)")
.onAppear {
Task {
while true {
try await Task.sleep(for: .seconds(1))
time += 1
}
}
}
// ๋ทฐ๊ฐ ์ฌ๋ผ์ ธ๋ ํ์ด๋จธ๋ ๊ณ์ ๋์๊ฐใ
ใ
}
}
๋ฉ๋ชจ๋ฆฌ ๋์ ๋๋ฒ๊น ํ ๐
- Xcode Memory Graph Debugger ์ฌ์ฉํ๊ธฐ:
- ์คํ ์ค ๋๋ฒ๊ทธ ์์ญ์์ ๋ฉ๋ชจ๋ฆฌ ๊ทธ๋ํ ๋ฒํผ ํด๋ฆญ
- ์์ฌ์ค๋ฌ์ด ๊ฐ์ฒด๋ค์ ์ฐธ์กฐ ๊ด๊ณ ํ์ธ
- Instruments์ Leaks ๋๊ตฌ ์ฌ์ฉํ๊ธฐ:
- ๋ฉ๋ชจ๋ฆฌ ๋์ ์๋ ํ์ง
- ์๊ฐ์ ๋ฐ๋ฅธ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ์ถ์
- deinit์ ๋ก๊ทธ ์ถ๊ฐํ๊ธฐ:์ด๋ ๊ฒ ํ๋ฉด ๊ฐ์ฒด๊ฐ ์ ๋๋ก ํด์ ๋๋์ง ํ์ธ ๊ฐ๋ฅ
deinit {
print("๐๏ธ \(type(of: self)) deinit ๋จ!")
}
์ ๋ฆฌ: ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐฉ์ง๋ฅผ ์ํ ์ฒดํฌ๋ฆฌ์คํธ โ
1. ๋น๋๊ธฐ ์์ ์ ์์ํ ๋ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ๊ณ ๊ด๋ฆฌํ๊ธฐ:
var currentTask: Task<Void, Never>?
func startWork() {
currentTask?.cancel()
currentTask = Task { ... }
}
deinit {
currentTask?.cancel()
}
2. ์ฅ๊ธฐ ์คํ ์์ ์ ์ทจ์ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค๊ธฐ:
while !Task.isCancelled {
// ์ฃผ๊ธฐ์ ์ผ๋ก ์ทจ์ ์ฌ๋ถ ํ์ธ
}
3. SwiftUI์์๋ .task ์์ ์ ํ์ฉํ๊ธฐ
4. ํด๋ก์ ์์ [weak self] ์ฌ์ฉํ๊ธฐ
5. ์์ ์๋ฃ ํ ์ฐธ์กฐ ํด์ ํ๊ธฐ:
dataTask = Task {
// ์์
์๋ฃ
self.dataTask = nil
}
Swift Concurrency๋ ์ ๋ง ๋ฉ์ง ๊ธฐ๋ฅ์ด์ง๋ง, ์ด๋ฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ์ฃผ์ํ์ง ์์ผ๋ฉด ์ฑ์ด ์ ์ ๋๋ ค์ง๊ฑฐ๋ ๋ฉ๋ชจ๋ฆฌ ๊ฒฝ๊ณ ๊ฐ ๋ฐ์ํ ์ ์์ด์. ์ ๋๋ก ์ดํดํ๊ณ ์ฌ์ฉํ๋ฉด ์ฑ์ ์ฑ๋ฅ๊ณผ ์์ ์ฑ์ด ํฌ๊ฒ ํฅ์๋ฉ๋๋ค! ๐ฏ
'๐ง๐ปโ๐ป Dev' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๐ SwiftUI์์ @Observable์ ์ฌ์ฉํ์ (0) | 2025.04.03 |
---|---|
SwiftUI Spacer ์ฌ์ฉ ๊ฟํ (0) | 2025.03.27 |
Swift Concurrency: async/await ์์ ์ ๋ณต ๐ (1) | 2025.03.11 |