[Swift Concurrency] Actors

Woozoo·2023년 5월 5일
0

[Swift Concurrency]

목록 보기
10/13

Two Different threads가 are accessing same Object할 때 문제가 생김

class MyDataManager {
    static let instance = MyDataManager()
    private init() { }
    
    var data: [String] = []
    
    func getRandomData() -> String? {
        
        self.data.append(UUID().uuidString)
        print(Thread.current)
        return data.randomElement()
    }
}

struct HomeView: View {
    let manager = MyDataManager.instance
    @State private var text: String = ""
    let timer = Timer.publish(every: 0.1, tolerance: nil, on: .main, in: .common, options: nil).autoconnect()
    
    var body: some View {
        ZStack {
            Color.gray.opacity(0.8).ignoresSafeArea()
            Text(text)
                .font(.headline)
        }
        .onReceive(timer) { _ in
            if let data = manager.getRandomData() {
                self.text = data
            }
        }
    }
}

홈뷰를 만들고 DataManager에서 0.1초마다 getRandomData가 호출되게 해줌

0.1초마다 uuid가 나오는 걸 볼 수 있는데
다른 탭인 BrowseView에서도 같은 로직을 이번엔 0.01초마다 가져오게 해봅시다

지금은 문제가 없음!
Main Thread에서 홈뷰도 브라우즈뷰도 동작하고 있어서


백그라운드로 태스크를 옮겨봅시다


홈뷰랑 BrowseView둘다 이렇게 만들어줌

이렇게 됐을 때 potential Thread 이슈가 생길 수 있겠죠

두 태스크가 지금 같은 객체를 바라보고 있으니까!

이거 Xcode에서 Thread sanitizer
Edit scheme에 추가해줄 수 있음


그리고 다시 실행해보면 이런 에러가 뜨는 걸 볼 수 있습니다!

이전에는 이렇게 completionHandler로 이런 문제들을 해결해줬었음


actor MyActorDataManager {
    static let instance = MyActorDataManager()
    private init() { }
    
    var data: [String] = []
    
    func getRandomData() -> String? {
        self.data.append(UUID().uuidString)
        print(Thread.current)
        return self.data.randomElement()
    }
}

이번엔 actor로 해결을 해봅시다

Task안에 로직을 추가해주면!
됩니다~



한 가지 알아둬야할 건 이제 actor로 선언한 manager의 경우 프로퍼티를 가지고 올 때도 async라고 뜨는 걸 볼 수 있음
그래서 actor의 프로퍼티를 가져올 때도 Task {}안에 감싸줘야한다는거?



만약에 async로 처리가 필요 없으면?
await이 필요없는데도 Task를 지금 감싸줘야하잖음
이럴 때 쓰는 키워드가

nonisolated 입니다~

캬~

프로퍼티도 가능함!!

또 알아둬야할 건 isolated로 선언된 건 actor내의 다른 async친구들을 가져올 수 가 없음

profile
우주형

0개의 댓글