프로그래밍iOS 개발자

스위프트에서 레이지 컬렉션(Lazy Collections)이란 무엇이며, 언제 사용하는 것이 적절한가요?

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

답변.

레이지 컬렉션(Lazy Collections)은 스위프트 2에서 도입된 특별한 메커니즘으로, 컬렉션에 대한 계산을 실제 결과에 접근할 때까지 미루는 기능을 제공합니다. 처음에 표준 컬렉션 메서드(예: map, filter)는 새로운 컬렉션의 완전히 계산된 결과를 반환했으며, 이는 대량의 배열이나 변환 체인 작업 시 불필요한 메모리 및 시간 소모로 이어질 수 있습니다.

문제는 중간 컬렉션의 과잉 생성입니다. 각 map 또는 filter 호출은 데이터의 새로운 복사본을 생성하여 여러 변환 시 프로그램의 성능을 감소시킵니다.

해결책.lazy 속성을 사용하여 레이지 컬렉션을 활용하는 것입니다. 스위프트는 모든 작업을 하나의 체인으로 결합하고 실제로 접근하는 요소만 계산합니다.

코드 예:

let array = Array(1...1_000_000) let result = array.lazy.filter { $0 % 2 == 0 }.map { $0 * 3 } print(result.prefix(5)) // 가장 처음 5개의 값만 계산됩니다

주요 특징:

  • 요소에 접근할 때만 계산이 수행됩니다(온디맨드).
  • map/filter 체인에서 중간 배열이 생성되지 않습니다.
  • 대량 데이터에서 메모리와 시간을 절약할 수 있습니다.

헷갈리기 쉬운 질문들.

질문 1: let b = a.lazy.map { ... }가 계산 결과를 즉시 반환하나요?

아니요, .lazy와 map/filter 메서드를 사용할 경우 데이터에 직접 접근할 때만 계산 결과가 반환됩니다(예: for-in, first, reduce를 통해).

코드 예:

let array = [1, 2, 3] let mapped = array.lazy.map { x in print("처리 중\(x)") return x * 2 } // 이 시점에서는 아무것도 출력되지 않습니다 let first = mapped.first // 여기서부터 계산이 시작되고 출력이 나타납니다

질문 2: .lazy 후에 원본 컬렉션에 새 요소를 추가하면, 이후에 결과에 접근할 때 그 요소도 처리되나요?

아니요, 레이지 컬렉션은 레이지 표현이 생성될 시점의 컬렉션 상태를 반영합니다. 이후에 추가된 요소는 고려되지 않습니다.

질문 3: 작은 컬렉션(<100 요소)에 .lazy를 사용하는 것이 효과적인가요?

아니요, 작은 컬렉션에서는 레이지 계산의 이점이 거의 보이지 않으며, 때때로 추가 오버헤드가 성능에 부정적인 영향을 미칠 수 있습니다.

일반적인 오류 및 안티 패턴

  • 레이지 체인 결과에 접근하는 것을 잊고 데이터가 이미 계산되었다고 생각합니다.
  • 작은 배열에서 .lazy를 사용하여 코드를 복잡하게 만들고 성능 이점을 얻지 못합니다.
  • 레이지 표현 생성 후 원본 컬렉션을 변경하고 변화가 반영되기를 기대합니다.

실제 사례

부정적 사례

프로젝트에서 모든 map/filter에 대해 무분별하게 .lazy를 사용했습니다.

장점:

  • 코드 스타일의 통일성.

단점:

  • 레이지 래퍼의 지속적인 생성으로 인해 성능이 저하되었습니다.
  • 계산이 이루어지지 않아 데이터가 제때 처리되지 않는 버그가 발생했습니다.

긍정적 사례

긴 변환 체인이 실제로 있는 함수에서만 .lazy를 적용하여 대규모 거래 데이터베이스의 보고서를 리팩토링했습니다.

장점:

  • 실행 시간이 눈에 띄게 단축되었습니다.
  • 특히 결과의 처음 몇 개 요소만 가져올 때 메모리 소비가 줄어들었습니다.

단점:

  • 해당 코드 부분에 대한 추가 문서화가 필요했습니다.