프로그래밍시니어 iOS 개발자

스위프트에서 static 및 class 속성은 어떻게 작동하며, 사용 시 어떤 문제점이 발생할 수 있으며, 스레드 안전한 static을 어떻게 구현할 수 있습니까?

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

답변.

Static 및 class 속성은 인스턴스가 아닌 유형에 속하는 속성입니다. 역사적으로 이들은 모든 인스턴스에 공통적인 정보를 저장하는 문제를 해결하기 위해 등장했습니다(예: 카운터, 구성을 위한 팩토리 등). 스위프트에서는 static을 모든 유형(class, struct, enum)에서 사용할 수 있지만, class는 클래스에서만 사용할 수 있으며 오직 계산된 속성에 대해서만 재정의할 수 있는 기능을 제공합니다.

문제: 잘못된 static 속성 사용은 경쟁 상태 및 여러 스레드에서 액세스할 때 오류를 초래할 수 있습니다. 또한 static과 class를 혼동하여 상속에서 재정의 메커니즘을 잘못 선택하기 쉽습니다.

해결책:

  • 변경 불가능하거나 명시적으로 스레드 안전한 속성에 대해서는 static을 사용하세요.
  • 상속 및 오버라이드를 위해서는 class 속성을 정의하세요.
  • 스레드 안전성을 위해 데이터는 프라이빗 static 저장소에 저장하고 동기화된 논리를 통해서만 접근하세요(예: DispatchQueue를 통해).

코드 예시:

class Counter { static var count = 0 static let queue = DispatchQueue(label: "counter.queue") static func increment() { queue.sync { count += 1 } } class var typeDescription: String { return "Generic Counter" } } class NamedCounter: Counter { override class var typeDescription: String { return "Named Counter" } }

주요 기능들:

  • static은 재정의할 수 없지만, class var은 재정의할 수 있습니다.
  • static은 모든 유형에서 작동하지만, class는 오직 클래스에서만 작동합니다.
  • 정적 속성은 유형당 하나의 복사본이 있으며, 코드의 어느 곳에서나 접근할 수 있습니다.

함정이 있는 질문들.

질문 1: static let 속성을 get으로 계산된 속성(computed property)으로 선언할 수 있습니까?

네, static 속성은 stored 또는 computed일 수 있습니다. let 속성의 경우 일반적으로 상수지만, static var는 충분히 계산된 속성이 될 수 있습니다:

struct Math { static var pi: Double { return 3.1415926 } }

질문 2: static var는 기본적으로 스레드 안전합니까?

아니요, static var가 여러 스레드에서 변경되면 경쟁 상태가 발생할 수 있습니다. 읽기/쓰기 작업은 수동으로 동기화되어야 합니다.

질문 3: class var를 stored 속성으로 사용할 수 있습니까?

아니요, class var는 항상 계산된 속성(get/optional set이 있는 속성)이어야 하며, stored 속성은 static에만 허용됩니다.

일반적인 오류 및 안티 패턴

  • 다중 스레드 환경에서 static var를 동기화 없이 두는 것.
  • stored class var를 선언하려고 하는 것.
  • static과 class를 혼동하여 상속을 위한 잘못된 메커니즘을 선택하는 것.

실제 사례

부정적인 사례

애플리케이션에서 사용자의 로그인 카운터가 static var에 저장되었고, 여러 스레드에서 동기화 없이 증가되었습니다.

장점:

  • 구현이 간단했습니다.

단점:

  • 결국 카운터가 때때로 잘못된 값을 주어 디버깅 및 버그 추적이 복잡해졌습니다.

긍정적인 사례

전역 구성 객체에는 static let을 사용하였고, 접근은 읽기 전용 또는 기록을 위한 DispatchQueue 사용으로 제한되었습니다.

장점:

  • 경쟁 상태가 없고 예측 가능한 동작을 보장합니다.
  • 스레드 안전성을 유지합니다.

단점:

  • 큐를 감싸는 코드로 인해 약간의 코드량이 증가했습니다.