티스토리 뷰

iOS/Swift

Swift, Equatable?

iOS 개발자, 였던 것 2023. 4. 21. 01:47

한 동안은 Swift 작업을 할 때 종종 사용했던 프로토콜에 대한 글을 쓰려고 한다.

그 중 첫 번째는 개인적으로 정말 많이 사용했던, Equatable이다.


Equatable

오늘도 어김없이, 공식 문서의 내용을 가져왔다.

Types that conform to the Equatable protocol can be compared for equality using the equal-to operator (==) or inequality using the not-equal-to operator (!=). Most basic types in the Swift standard library conform to Equatable.

 

간단하게 이야기하면, 비교 연산자들을 통해 비교 할 수 있도록 만들어주는 프로토콜을 의미하는데 스위프트에서 제공되는 자료형들이 기본적으로 채택하고 있어 각각이 비교 연산이 가능하도록 해준다고 한다.

 

Some sequence and collection operations can be used more simply when the elements conform to Equatable. For example, to check whether an array contains a particular value, you can pass the value itself to the contains(_:) method when the array’s element conforms to Equatable instead of providing a closure that determines equivalence. The following example shows how the contains(_:) method can be used with an array of strings.

 

배열이나 콜렉션 등에서 해당 프로토콜을 지원하는 값들을 사용하고 있다면, contains를 통해 이를 비교하는 것 또한 가능하다.

외에도, Equatable을 struct나 class에서 채택하려면, 내부에 있는 값들도 모두 Equatable 해야 가능하다고 한다.

 

오늘은 코드를 작성해서 가져와 보았다.

쇼핑카트에 아이템을 담는다고 가정하고, 쇼핑 카트에 들어갈 아이템을 정의했다.

struct CartItem : Equatable {
    let id : String
    let name : String
    let basePrice : Int
    var price : Int
    var count : Int {
        didSet {
            price = count * basePrice
        }
    }
    
    init(id: String, name: String, basePrice: Int) {
        self.id = id
        self.name = name
        self.basePrice = basePrice
        self.price = basePrice
        self.count = 1
    }
    
    static func == (lhs: CartItem, rhs: CartItem) -> Bool {
        return lhs.id == rhs.id
    }
}

위와 같은 형태로 CartItem이라는 구조체를 만들었다. 

count 뒤에 붙어있는 didSet은 property observer로 해당 프로퍼티의 값이 변하는 경우에 작동하는 옵저버이다. 자세한 건 추후에!

Equatable이라는 프로토콜을 채택하면, 자연스레 == 연산자를 사용할 수 있게 된다.

 

혹시, Equatable을 채택했는데 == 연산자가 안됩니다! 라고 하면 struct가 아니라 class를 사용 중인지 확인해보자

struct의 경우는 Swift 기본 자료형만을 property로 가지고 있다면, property들 전체를 비교해주는 기본 == 연산자가 정의가 되지만, class의 경우에는 어림도 없지! 내가 구현해주어야 한다. 참고로 enum도 구현 없이 사용이 가능하다.

 

== 연산자야 워낙 사용사례가 많아서 보기만 해도 어디에 사용될 지 알 듯 하지만, 상품을 만든 김에 장바구니까지 겸사겸사 만들어보았다.

아래는 장바구니 로직을 간단하게 정리한 도식이다.

작고 귀여운 장바구니 로직

그리고 이를 코드로 만들면, 아래와 같은 코드가 탄생한다.

var shoppingCart : [CartItem] = []
func appendCartItemToCart(item: CartItem) {
    if let idx = shoppingCart.firstIndex(of: item) {
        shoppingCart[idx].count += 1
    } else {
        shoppingCart.append(item)
    }
}

카트내의 아이템을 id 값으로 비교, 동일한 아이템이 있다면 해당 값의 인덱스를 가지고와 총 갯수를 변경해주고, 아니라면 신규 아이템을 추가해주는 부분이다. 이때 firstIndex에서 사용되는 메소드가 equatable로 정의되어 있는 비교 연산자이다.

 

만들었으니 안돌려 볼 수 없지 않겠는가? 간단한 실행 코드이다.

appendCartItemToCart(item: CartItem(id: "item-01", name: "아메리카노", basePrice: 4000))
// item-01이라는 id를 가진 아메리카노가 카트에 추가됨

appendCartItemToCart(item: CartItem(id: "item-02", name: "아메리카노", basePrice: 3500))
// item-02이라는 id를 가진 아메리카노가 카트에 추가됨

appendCartItemToCart(item: CartItem(id: "item-01", name: "아메리카노", basePrice: 4000))
// item-01이라는 id를 가진 아메리카노는 이미 카트에 있으므로, 갯수만 더해짐
// 이때 didSet이 작동하면서, 값도 같이 바꾸어 줌

 

 

 

 

주석으로 달아둔 설명처럼 처음 두 아메리카노는 이름은 같지만, id가 다른 개별적인 상품이므로 서로에게 영향을 주지 않고 마지막 세번째에 들어오는 아메리카노는 처음 들어온 아메리카노와 id가 같아 같은 상품으로 취급, count 값만 변경하게 되고 이 때 앞에서 설정해둔 property observer가 작동해 총 가격을 변경해주는 것 까지가 코드의 시나리오이다.

 

소스코드의 실행 결과

실제 결과를 한 번 보자, 처음에는 id값이 달라 따로 들어갔지만 마지막 아메리카노가 들어왔을 때 array 내에 추가되는 것 없이 상품의 갯수와 가격만 변한 것을 확인 할 수 있다. 

 

실무에서도 꽤나 많이 사용했고, 이를 통한 비교를 할 일이 많았던 만큼 가장 빠르게 작성한 글이었다.

시간이 많이 남아서 코드도 짜고 내용도 추가했을 정도, 코드를 직접 짜보는게 복습하는데도 도움이 더 많이 되는 만큼

앞으로는 과거의 코드를 찾아서, 이를 리팩토링 하면서 적용해 볼 까 한다.

 

 

'iOS > Swift' 카테고리의 다른 글

Swift에서의 Class와 Struct  (0) 2023.04.27
Swift, Set 톺아보기  (0) 2023.04.18
ViewController와 LifeCycle - 2, LifeCycle  (0) 2023.04.18
ViewController와 LifeCycle - 1, UIViewController  (0) 2023.04.16
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함