반응형

Swift에서 for-in vs 인덱스 기반 반복(0..<array.count)

 

Swift에서는 배열이나 컬렉션을 순회할 때 두 가지 주요 방식이 있습니다.

  1. for-in 반복문
  2. 인덱스 기반 반복문 (0..<array.count)

Swift 공식 문서와 WWDC 세션, Swift Forums의 논의를 종합하면 다음과 같은 이유로 for-in이 기본 권장 방식입니다.

 

1. for-in이 권장되는 이유


1.1 언어 차원의 1급 순회 구문

Swift 표준 문서(Sequence)에는 다음과 같이 명시되어 있습니다.

The most common way to iterate over the elements of a sequence is to use a for-in loop.

즉, 시퀀스를 순회하는 가장 일반적이고 권장되는 방법은 for-in입니다.

1.2 안전성과 가독성

  • 인덱스 범위 체크(Out of Range) 오류 위험이 없습니다.
  • 값만 필요할 때 코드가 명확하고 의도가 바로 드러납니다.
  • Swift 컴파일러는 for-in을 내부적으로 최적화하여 IndexingIterator를 효율적으로 사용합니다.

1.3 최적화 수준

Swift Forums의 엔지니어 논의(Performance of array access vs iterator)에 따르면,
배열 순회 시 for element in array가 가장 효율적으로 컴파일됩니다.
컴파일러가 내부적으로 최적의 반복 코드를 생성하기 때문입니다.

for element in array {
    print(element)
}

 

2. 인덱스가 필요한 경우의 올바른 대안


2.1 enumerated() 사용

인덱스와 값을 동시에 사용해야 한다면 enumerated()를 활용합니다.

for (i, value) in array.enumerated() {
    print("Index: \(i), Value: \(value)")
}
  • 0부터 시작하는 연속 정수 인덱스와 요소 쌍을 반환합니다.
  • 공식 문서: Array.enumerated()

2.2 indices 속성 사용

컬렉션 고유 인덱스 타입을 직접 사용해야 한다면 indices를 활용합니다.

for i in array.indices {
    let value = array[i]
    print("Index \(i): \(value)")
}
  • 공식 문서: Collection.indices
  • indices는 컬렉션의 실제 인덱스 타입(Array.Index, String.Index 등)을 반환합니다.
  • String은 정수 인덱스를 사용하지 않기 때문에 indices 접근이 필수적입니다.
for i in text.indices {
    print(text[i])
}

참고: String.indices

 

3. 인덱스 기반 루프 (0..<array.count)

for i in 0..<array.count {
    print(array[i])
}

⚠️ 주의할 점

  • Array에서는 동작하지만, 다른 컬렉션(Set, Dictionary, String)에서는 정수 인덱스가 유효하지 않습니다.
  • 값만 필요할 때는 불필요하게 인덱스를 다루는 셈이므로 가독성과 안전성이 낮습니다.
  • 오프바이원(Off-by-one) 실수가 발생하기 쉽습니다.

→ 따라서 단순 요소 순회에는 for-in을 사용하고, 인덱스가 필요한 경우에만 enumerated() 또는 indices를 선택하는 것이 권장됩니다.

 

4. 성능 비교

방식 복잡도 컴파일러 최적화 안정성 권장 여부
for element in array O(n) ✅ 최고 수준 ✅ 안전 ✅ 권장
for (i, v) in array.enumerated() O(n) ✅ 효율적 ✅ 안전 ✅ 권장
for i in array.indices O(n) ✅ 효율적 ✅ 안전 ✅ (특수 케이스)
for i in 0..<array.count O(n) ⚠️ 동일하지만 범위 객체 생성 ❌ 위험 🚫 비권장

 

5. 성능 분석 (Swift Forums 및 Apple 문서 기반)

  • Swift 컴파일러는 for-in 루프를 내부적으로 IndexingIterator 기반으로 변환합니다.
    (IteratorProtocol, IndexingIterator)
  • 이는 직접 인덱스를 다루지 않으므로 안전하면서도 빠릅니다.
  • for-in은 ARC 최적화와 함께 인라인 루프가 자동 적용되어 C 수준의 반복 성능을 제공합니다.

참고: “for-in loop over array is the most efficient way to iterate an array” — Swift Forums (2016)

 

6. 예외적으로 인덱스가 유리한 상황

  • 이웃 요소 간 비교가 필요한 경우 (슬라이딩 윈도우)
  • 특정 위치의 값만 업데이트해야 할 때
  • 로그나 디버깅용으로 인덱스와 값을 함께 출력해야 할 때

이런 경우에도 enumerated() 또는 indices가 선호됩니다.

 

7. 공식 문서 링크 모음

항목 문서 링크
Sequence 프로토콜 https://developer.apple.com/documentation/swift/sequence
Array.enumerated() https://developer.apple.com/documentation/swift/array/enumerated
Collection.indices https://developer.apple.com/documentation/swift/collection/indices
String.indices https://developer.apple.com/documentation/swift/string/indices
IndexingIterator https://developer.apple.com/documentation/swift/indexingiterator
IteratorProtocol https://developer.apple.com/documentation/swift/iteratorprotocol
Swift Forums - Iteration 성능 논의 https://forums.swift.org/t/performance-of-array-access-vs-iterator/6265

 

8. 결론

상황 권장 방법 이유
단순 순회 for element in array 가장 빠르고 안전
인덱스 + 값 필요 for (i, v) in array.enumerated() 가독성, 안정성
컬렉션 고유 인덱스 필요 for i in array.indices 실제 인덱스 접근
정수 인덱스만 필요 for i in 0..<array.count 제한적(배열만 해당)

 요약:

Swift에서는 가능한 한 for-in을 기본 사용하고, 인덱스가 필요한 경우 enumerated() 또는 indices를 사용하라.

직접 정수 인덱스 반복은 호환성, 안전성, 유지보수성 모두에서 불리하다.

 

반응형
Posted by 까칠코더
,