[SWIFT] ArraySlice

2022. 2. 25. 19:51SWIFT

반응형

그동안 개발을 하면서 Swift에서 Array를 나누게 되면 생길 수 있는 ArraySlice라는 타입이 있는데, 여기에 대해 스터디를 하다 궁금증이 생겨서 정리해보려고 합니다 👋

 

ArraySlice

Array를 다루다보면 볼 수 있는 타입인데, 사실 뭔가 미묘했다. 분명 Array인데...(?) 왜 굳이 나눠서 따로 있는거고 그냥 Array를 사용하면 되지 않는가 의문이 생겼다. 특히, 보통 사용할 때, Array로 캐스팅하는 과정을 거쳤었다 🤔

 

우선 공식 문서에 설명을 보면 다음과 같습니다.

Array, ContiguousArray, ArraySlice의 Slice라고 설명되어 있습니다. 즉, Array를 잘라도 ArraySlice이고 ContiguousArray, ArraySlice를 모두 잘라도 ArraySlice라는 것입니다. 그리고 ArraySlice에서도 Array와 동일한 인터페이스를 제공하기 때문에, 동일한 작업도 가능하다고 하고 있네요. 

 

더더욱 왜 굳이 나누는지 모르겠죠..? 🥲

 

공식문서를 보면 설명이 나오고 있는데, ArraySlice를 사용하면 큰 배열에서 작업을 더 효율적으로 할 수 있고 내의 Element들을 새롭게 복사해서 저장하는 것이 아닌(copy on write) 기존 배열에 대한 보기를 제공한다고 하고 있어요. 

 

기존에 배열은 copy on write 방식으로 새롭게 이동 및 생성하기 위해서 메모리를 그만큼 할당하고 옮기는 작업이 있어야 하는데, ArraySlice를 사용하면 레퍼런싱을 해서 그런 과정들이 필요없어서 효율적인 것 같습니다!

 

즉, ArraySlice는 배열을 나누어서 작업하는데 기존의 Array 처럼 copy on write 방식이 아닌 레퍼런싱만을 제공해서 활용할 수 있다는 것과 Arrray와 동일한 인터페이스로 작업할 수 있다는 점에서 효율적이라는 것입니다.

 

그렇다면, 애플에서 제공하는 예제를 한 번 보겠습니다~

let absences = [0, 2, 0, 4, 0, 3, 1, 0]

let midpoint = absences.count / 2

let firstHalf = absences[..<midpoint]     // ArraySlice
let secondHalf = absences[midpoint...]    // ArraySlice

이렇게 결석자들이 있고 반반으로 나누어서 더 많은 결석자가 있는 부분을 알고 싶을 때, 다음과 같이 작성이 가능해집니다..!!

let firstHalfSum = firstHalf.reduce(0, +)
let secondHalfSum = secondHalf.reduce(0, +)

if firstHalfSum > secondHalfSum {
    print("More absences in the first half.")
} else {
    print("More absences in the second half.")
}
// Prints "More absences in the first half."

오.. ArraySlice에서 기존의 Array와 같은 reduce 인터페이스에 접근이 가능하고 사용이 되죠?

분명 같은 인터페이스를 사용할 수 있으면서도 메모리를 그만큼 할당하고 복사하는 것이 아니기 때문에 효율적일 것 같네요.

 

다만, 주의해야할 점이 있는 것 같습니다

분명 ArraySlice는 기존 Array에 대한 레퍼런싱을 제공한다고 했죠?!

그렇기 때문에, ARC로 동작하는 Swift에서 메모리 릭이 발생할 수 있는 구멍이 되는 것 같습니다. 

장기적인 ArraySlice 인스턴스 보관은 권장하지 않습니다. ArraySlice는 기존 Array의 저장장소를 레퍼런싱하기 때문에 Array의 생명주기가 끝나고 나서도 ArraySlice가 소멸되지 않으면 메모리 릭이 발생할 수 있습니다.

 

Slices Maintain Indices

다음은 ArraySlice를 사용하면서 주의(?)보다는 유의해야하는 부분입니다.

바로 Index에 관한 부분입니다. 공식문서에 의하면 ArraySlice의 시작 인덱스는 Array와 다르게 항상 0이 아니라고 합니다. 

ArraySlice는 기존에 잘라지기 전의 Array와 동일한 index를 유지하고 있다고 합니다. 즉, ArraySlice의 시작 Index는 기존에 어떻게 생성되었는지에 의존해서 부여된다고 합니다.

 

말로만 해서는 잘 감이 오지 않으니 예시로 알아볼게요

let absences = [0, 2, 0, 4, 0, 3, 1, 0]

if let i = absences.firstIndex(where: { $0 > 0 }) {                 // 1
    let absencesAfterFirst = absences[(i + 1)...]                   // 2
    if let j = absencesAfterFirst.firstIndex(where: { $0 > 0 }) {   // 3
        print("The first day with absences had \(absences[i]).")    // 4
        print("The second day with absences had \(absences[j]).")
    }
}
// Prints "The first day with absences had 2."
// Prints "The second day with absences had 4."

분명 첫번째 조건에서 index가 1이 나왔습니다. 그렇다면 다음 2부터 [0, 4, 0, 3, 1, 0]의 ArraySlice가 만들어지고 여기서 0보다 큰 first Index를 찾게 되면 두번째에 있어서 j = 1이 되어야 하는데, 3이 출력되죠..?!

 

아.. 처음에 Array의 index가 유지되는구나..😵‍💫

이렇게 ArraySlice를 사용할 때, 뭔가 index를 이용해서 사용해야하는 경우는 유의해야겠죠?! 

 

애플에서는 startIndex, endIndex라는 프로퍼티를 활용하라고 권고하고 있습니다..!

 

오늘은 이렇게 ArraySlice에 대해서 간단히 알아보았습니다

혹시 잘못된 정보나 궁금한 점이 있으면 댓글 남겨주세요 🥲

 

반응형

'SWIFT' 카테고리의 다른 글

[Swift] Codable (2)  (0) 2022.09.14
[Swift] Codable (1)  (0) 2022.04.24
[SWIFT] String Compare (앱 버전 비교)  (0) 2021.10.10
[SWIFT] KVO (Key - Value - Observing)  (0) 2021.09.26
[SWIFT] KVC (Key - Value - Coding)  (0) 2021.09.20