How to use async / await keywords in Swift | Swift Concurrency #3
Async
, Await
를 사용할 때의 스레드 환경 파악하기Actor
를 활용한 스레드 환경 조정하기sleep
등 비동기 함수를 실행한 이후 스레드 환경 파악하기MainActor
내부의 스레드 상황 파악하기 func addSomething() async {
try? await Task.sleep(nanoseconds: 2_000_000_000)
let something1 = "Something1 : \(Thread.current)"
await MainActor.run(body: {
self.dataArray.append(something1)
let something2 = "Something2 : \(Thread.current)"
self.dataArray.append(something2)
})
}
...
Task {
await viewModel.addAuthor1()
await viewModel.addSomething()
let finalText = "FinalText : \(Thread.current)"
viewModel.dataArray.append(finalText)
}
Task.sleep
메소드는 throw
가능한 비동기 함수로 해당 코드를 실행한 이후의 스레드는 메인 스레드가 아님MainActor
내부에서의 스레드 환경은 언제나 메인 스레드(애플 프레임워크 내부의 싱글턴 객체)Task
를 통해 await
대기 가능import SwiftUI
class AsyncAwaitBootCampViewModel: ObservableObject {
@Published var dataArray = [String]()
func addTitle1() {
dataArray.append("TITLE1 : \(Thread.current)\nIs Main? : \(Thread.isMainThread)")
}
func addTitle2() {
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
let title2 = "TITLE2 : \(Thread.current)\nIs Main? : \(Thread.isMainThread)"
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.dataArray.append(title2)
self.dataArray.append("Title3: \(Thread.current)\nIs Main? : \(Thread.isMainThread)")
}
}
}
func addAuthor1() async {
let author1 = "Author1 : \(Thread.current)"
self.dataArray.append(author1)
try? await Task.sleep(nanoseconds: 2_000_000_000)
// after sleep -> thread : not main thread
// try? await doSometing()
// await -> suspension point
let author2 = "Author2: \(Thread.current)"
// after sleep -> thread : main thread
await MainActor.run(body: {
self.dataArray.append(author2)
let author3 = "Author3: \(Thread.current)"
self.dataArray.append(author3)
})
await addSomething()
}
func doSometing() async throws {
print("do Something")
}
func addSomething() async {
try? await Task.sleep(nanoseconds: 2_000_000_000)
let something1 = "Something1 : \(Thread.current)"
await MainActor.run(body: {
self.dataArray.append(something1)
let something2 = "Something2 : \(Thread.current)"
self.dataArray.append(something2)
})
}
}
Task.sleep
을 통해서는 현 스레드(메인)가 다른 스레드로 바뀌지만 doSomething
이라는 함수를 통해서는 바뀌지 않음 → async
함수라 할지라도 스레드 환경이 코드에 따라 달라짐struct AsyncAwaitBootCamp: View {
@StateObject private var viewModel = AsyncAwaitBootCampViewModel()
var body: some View {
List {
ForEach(viewModel.dataArray, id:\.self) { data in
Text(data)
.font(.headline)
.fontWeight(.bold)
}
}
.onAppear {
Task {
await viewModel.addAuthor1()
await viewModel.addSomething()
let finalText = "FinalText : \(Thread.current)"
viewModel.dataArray.append(finalText)
}
}
}
}
현재 UI를 담당하는 있는 데이터 서비스의 코드가 실행되는 스레드가 메인 스레드인지 확인 필수. 동일한 객체에 비동기적으로 접근하고 있는 코드가 두 개 이상이라면
actor
클래스를 통해 동기화 적용 가능하다는 데 주의하자