프로그래밍iOS 개발자

스위프트에서 lazy 속성의 주요 차이점은 무엇인가요? 언제 lazy를 사용해야 하며, 초기화 시의 특징과 함정은 무엇이 있으며, 전형적인 문제를 피하려면 어떻게 해야 하나요?

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

답변.

스위프트의 lazy 속성은 처음 접근할 때만 계산됩니다. 이는 자원이 많이 드는 객체(예: 무거운 계산, 네트워크 로드)와 같이 즉시 필요하지 않은 경우에 자주 사용됩니다. lazy 키워드를 사용하여 선언됩니다:

class DataFetcher { lazy var data: Data = self.loadData() func loadData() -> Data { /* … */ } }

특징 및 주의 사항:

  • lazy 속성은 변수(var)에 대해서만 허용되며, 상수(let)에 대해서는 허용되지 않습니다.
  • 구조체 내부에서는 lazy 속성이 작동하지 않으며, 구조체가 immutable일 경우 사용할 수 없습니다.
  • 다른 스레드에서 set하는 경우 스레드 안전하지 않습니다. 서로 다른 스레드에서 lazy 속성에 동시에 접근하는 것을 피해야 합니다.
  • 클래스 객체를 복사할 때, lazy 값은 각 인스턴스 별로 캐시됩니다.

속임수가 있는 질문.

질문: "클래스 인스턴스가 초기화될 때 lazy property의 값이 생성되나요?"

답변: 아니요, 값은 속성에 처음 접근할 때만 계산되며, 초기화 시점에서는 계산되지 않습니다.

class Expensive { init() { print("init") } } class Example { lazy var heavy = Expensive() } let foo = Example() // 아무 출력도 없음 _ = foo.heavy // 이제 "init"

주제의 미세한 차이로 인한 실제 오류 사례.


이야기

두 플랫폼을 위한 프로젝트에서 이미지 캐시를 저장하기 위해 lazy 배열을 사용했습니다. 여러 스레드에서 동시에 접근할 때 경합 조건이 발생했으며, lazy var를 뮤텍스(mutex)로 감쌌지만 lazy를 잊어버려서 앱이 충돌하게 되었습니다.


이야기

어린 개발자가 무거운 계산을 캐시하기 위해 lazy let을 선언하려고 했습니다. 코드가 컴파일되지 않았으며, lazy는 var에 대해서만 허용되기 때문에 아키텍처를 재검토해야 했습니다.


이야기

개발자가 초기화 시 closure 내부에서 self를 캡처하여 lazy 속성을 선언했습니다. 이로 인해 순환 참조가 발생하여 객체는 모든 화면에서 나가더라도 비해제되지 않았습니다.