프로그래밍iOS 개발자

Swift에서 변경 가능한 데이터와의 스레드 안전한 상호작용을 어떻게 구현합니까? 잘못된 구현으로 인해 발생할 수 있는 접근 방식과 문제를 설명하십시오.

Hintsage AI 어시스턴트로 면접 통과

답변

Swift에서 스레드 안전성을 보장하기 위해 종종 GCD(Grand Central Dispatch) 및 큐(DispatchQueue), NSLock, 그리고 Swift 5.5부터의 현대적 메커니즘인 actor를 사용합니다.

주요 아이디어 - 변경 가능한 데이터에 대한 접근은 반드시 순차 큐를 통해 엄격하게 이루어지거나 동기화기(잠금)을 사용해야 합니다.

GCD 예제:

class ThreadSafeArray<Element> { private var array: [Element] = [] private let queue = DispatchQueue(label: "com.example.arrayQueue", attributes: .concurrent) func append(_ item: Element) { queue.async(flags: .barrier) { self.array.append(item) } } func get(index: Int) -> Element? { var result: Element? queue.sync { result = self.array.indices.contains(index) ? self.array[index] : nil } return result } }

현대적 접근: Actors (Swift 5.5+):

actor SafeCounter { private var value = 0 func increment() { value += 1 } func get() -> Int { return value } }

두 접근 방식 모두 데이터 경쟁을 피하고 상태 일관성을 유지할 수 있게 해줍니다.

함정 질문

질문:

만약 Main Queue 내부에서 DispatchQueue.sync를 사용한다면, 무슨 일이 발생하며 그 이유는 무엇인가요?

답변: 교착 상태(Deadlock)가 발생할 것입니다. 이는 Main Queue가 이미 작업을 수행 중이며 같은 큐에서 동기 작업의 완료를 기다리고 있기 때문입니다. 따라서 현재 작업이 완료되지 않는 한 대기 중인 다음 작업을 처리할 수 없게 됩니다.

예제:

DispatchQueue.main.sync { // 교착 상태: 이 줄은 절대 실행되지 않습니다. }

주제에 대한 미세한 지식 부족으로 발생한 실제 오류의 예


이야기

프로젝트에서 동기화 없이 여러 스레드에서 동시에 접근하는 변경 가능한 컬렉션을 사용했습니다. 이로 인해 데이터 경쟁으로 인한 애플리케이션 충돌 및 잡히지 않는 버그가 발생했으며, 특정기간마다 요소가 손실되거나 배열의 경계를 초과하는 경우가 발생했습니다.


이야기

개발자가 런타임에서 Main Queue에 대해 DispatchQueue.sync를 잘못 사용하여 교착 상태가 발생하고 업데이트 후 사용자 UI가 완전히 중단되었습니다. 긴급한 수정 및 출시 롤백이 필요했습니다.


이야기

NSLock을 사용하여 클래스를 스레드 안전하게 만들려고 시도했지만, 메소드의 모든 종료 경로에 대해 lock/unlock을 구현하는 것을 잊어버려 교착 상태의 잠재성과 애플리케이션 성능에 심각한 문제를 일으켰습니다.