SwiftUI) ForEach (feat. forEach(_:)) 톺아보기 01 | change-challenge

장호진·2023년 4월 14일
0

swift

목록 보기
2/3

SwiftUI를 한번 맛보기 위해 iOS APP Dev Tutorials를 한번 돌리고 있는 중에 ForEach를 사용하려면 요소들을 identifiable하게 만들어야한다고 한다.

아니 도대체 반복문 돌리는데 왜 identifiable하게 만들어야한다는거야???
고민하다가 반복문 할 때 사용하는 메소드 forEach(_:)와 다르다는 것을 깨달았다...

심지어 하나는 Structure이고, 하나는 Method이다.

내가 알았던 것은 아래의 forEach(_:)이고,

이것이 SwiftUI에서 사용하는 ForEach이다.

(도대체.. 왜 이름을 같게 한거야..)


메소드 : forEach(_:)

먼저 우리가 잘 아는 친구부터 보자.

forEach는 For-in을 쉽게 사용할 수 있는 메소드로 사용된다.

애플 공식 documentation에서는 위와 같이 정의 되어있다.

내부를 살펴보면 forEach는 하나의 throw 클로저를 받는 메소드이다.
(throw 클로저가 아니여도 가능합니다.)

하지만, throw 클로저를 인자로 넘긴다면 어떻게 해야할까?
rethrows 키워드를 쓰고 있기에, 클로저 내부에서 에러 발생 시, 클로저 내부에서 직접 처리하지 않고 해당 forEach를 호출한 쪽으로 에러를 전달합니다.

forEach를 호출한 쪽에서 try문이나 do-catch문을 작성해줘야합니다.

예시)

enum CalculationError: Error {
    case divideByZero
}

func divide(_ a: Int, _ b: Int) throws -> Int {
    guard b != 0 else {
        throw CalculationError.divideByZero
    }
    return a / b
}

let numbers = [10, 20, 30, 0, 40]

// 클로저가 에러를 던지지 않는 경우, try-catch 블록을 사용하지 않아도 됩니다.
numbers.forEach { number in
    let result = try? divide(100, number)
    print(result ?? "Error")
}
<출력 >

10
5
3
Error
2

이것이 우리가 자주 쓰는 forEach이다.

짧게 특징까지 이야기하면,
1. for-in문이 아니기 때문에 breakcontinue는 쓰지 못한다.
2. 클로저 내부에서 return을 쓰게 되면 한 순서만 끝나는 것이다. 모든 forEach 메소드가 끝나는 것이 아니다.

예시)

let numbers = [1, 2, 3, 4, 5]

numbers.forEach { number in
    if number == 3 {
        return
    }
    print(number)
}

<출력 >

1
2
4
5

forEach에서 returncontinue처럼 쓸 수 있다고 생각하면 될 것 같다.


구조체 : ForEach

일반적으로 SwiftUI에서 ForEach는 주어진 collection을 기반으로 View를 반복해서 만들어준다.
(헷갈리게 스펠링에서 f의 대문자 하나 다르다.)

애플 공식 documentation에서는 아래와 같이 프로토타입이 정해져있다.

프로토타입을 해석하는 것을 즐거워하기에 하나씩 해석을 해보겠습니다!

1️⃣. <Data, ID, content>

제네릭 변수 Data, ID, Content를 사용하겠다는 것이다.
C++에서는 < T >라고도 적는데 Swift에서는 명확한 이름을 사용해 가독성을 높이고 있습니다.

2️⃣. where Data: RandomAccessCollection, ID : Hashable

먼저 where 키워드는 제네릭 타입 매개변수에 대한 제약 조건을 추가하는 역할을 합니다.
즉, 이 키워드를 사용하면 특정 조건을 만족하는 타입만을 받아들일 수 있도록 제한할 수 있습니다.

예를 들어, 이 곳에서는

DataRandomAccessCollection 프로토콜 준수하고
IDHashable 프로토콜을 준수한 타입만 받아드리겠다는 것이다.

3️⃣. RandomAccessCollection (랜덤 엑세스 콜렉션)

Swift에서 RandomAccessCollection은 Collection 프로토콜을 상속받는 프로토콜입니다.
RandomAccessCollection은 Collection 프로토콜의 모든 요구사항을 충족하면서, 해당 컬렉션의 모든 요소를 O(1) 시간 내에 접근할 수 있는 요구사항을 추가적으로 갖습니다.
즉, 바로 linked List말고 바로 []로 접근가능한 것들이 RandomAccessCollection입니다.

가장 가까운 예시로는 Array가 있습니다.
애플 공식 Documentation에서 보면 아래와 같이 random-access collection이라고 적혀있습니다.

빠르게 접근할 수 있고, 데이터를 검색하거나 정렬하는 등의 작업에서 효율적입니다.

4️⃣. Hashable (해쉬블)

Hashable 프로토콜은 Swift의 표준 라이브러리에서 제공하는 프로토콜 중 하나로, 객체를 해싱(Hashing) 가능하게 만드는 데 사용됩니다.

해싱은 임의의 길이의 데이터를 고정된 길이의 값으로 매핑하는 것을 말하며,
해시(Hash)는 이러한 매핑된 값을 의미합니다.

이것을 이해하려면 이런 상황을 떠올리면 좋다.

Person이라는 Struct가 있다
Person 내부 변수로 대략 1,000개가 있다고 하자.

이 PersonA와 PersonB를 같나 틀리나라는 operator==를 쓰려고하는데
하나 하나 다 검사하는 것이 효율적일까?

해시는 데이터의 고유한 식별자를 만들어내는 것으로, 객체를 해싱 가능하게 만들면, 해당 객체를 빠르게 비교하고 검색할 수 있습니다.
해시를 사용하면, 위에 Person과 같은 상황도 빠르게 처리할 수 있습니다.

Set이나 Dictionary의 key값도 중복이 되면 안되고, 이것을 빠르게 처리하기 위해 Hash table을 사용한다고 한다.

(낄낄낄.. 이제 프로토타입의 기본을 안 것이다.)

길이 엄청 길어지네.. 역시 깊게 공부하려고 노력하면 재밌는데 길어진다.
가독성을 위해 두 번째 글을 작성해보겠습니다.🙋🏻‍♂️

profile
도전하고, 바꾸고

0개의 댓글

관련 채용 정보