본문 바로가기

iOS/Swift

Swift) Comparable에 대해 알아보자

 

 

 

안녕하세요 :) 소들입니다

일요일인데 포스팅 쓰러 카페에 왔습니다!!!!!!

제가 한 3주 정도 현업 때문에 정말 너무너무 바빴어서..;;

 

 

사실 풀 재택근무중인데

굳이 회사나가서 새벽까지 개발하면 그게 또 그 낭만이 있그든요

 

 

그랬다고 한다 ㅋ

쨌든 금요일에 qa 배포를 하고 나서야 사람의 인생이 되었어요 

해방이다~~~~~~!(라 쓰고 이제 버그와의 전쟁이라 읽는다)

 

이번주에는 글을 무려 2개나 작성해야 하기 때문에!!

마지막으로 comparable이란 프로토콜에 대해 공부해보려고 해요 :)

이로써 알아두면 유용한 프로토콜 3대장에 대해 마무리르 지어볼까 함니다

 

요즘 공부하고 싶은 내용을 추천받고 있는데

일단 1. 메타타입 2. async/await 이 두개에 대해 생각해보고 있긴 해요

만약 원하는 내용이 있으면 언제든 댓글 달아주셔요!!!(안 할 수 도 있 음)

모든 포스팅은 편의 말투로 합니다~!

 

 

 

 

1. Comparable : 대소비교 하기 위해 채택해야 하는 프로토콜이겠지 뭐... 낄낄

 

핵심 프로토콜 공부 마지막 시간이니까

거두절미하고 핵심만 얘기 하겠음 ㅎㅎ;

이름만 봐도 느낌이 오지 않음? 자 우리가 사용하는 비교 연산인

 

>

<

>=

<=

 

넹 이것들 있잖음??

이것들을 사용하기 위해선 바로 Comparable이란 프로토콜을 준수하고 있엉 ㅑ함

우리가 이렇게 Int 타입의 두 가지를 비교할 수 있던 이유는

 

 

let num1 = 10
let num2 = 20
 
num1 > num2         // false
num1 <= num2        // true

 

 

앜 Comparable 때문이란 거지?

그리고 기본 자료형은 자동으로 컴파일러가 Comparable을 준수한다고 하니 저게 된느거고?

맞음!! 근데 궁금하지 않음?? Int형이나 뭐 Double이런 건 비교가 단순하니가 그렇다 쳐도

String은 그럼 어떻게 비교룰 할까?

 

 

let str1 = "a"
let str2 = "A"
let str3 = "b"
 
 
str1 > str2     // true
str1 > str3     // false

 

 

String의 경우엔 이또한 기본 자료형이라 Comparable을 자동채택하고 있어서

별 문제 없이 >를 사용할 수 있지만, 이때 대소비교에 대한 기준이 되는 것은 

 

 

 

 

유니코드 값이 기준임!! 따라서 a가 b보다 유니코드 값이 작기 때문에

"a" > "b" 값이 false가 되는 것임 ㅎㅎ 

또한, Swift에선 대/소문자를 구분하기 때문에

"a" > "A" 값은 true가 되는 것임!!! 

아니 뭐 누군가는 모를 수도 있으니까 설명 해봄

 

Comparable이 어떻게 생긴 놈인지 봐보자면,

 

 

 

 

Equatable을 채택하고 있네!??!!?

 

여러분 우린 이제 프로토콜 3트차니까 눈치가 생겼어요

우리가 직접 만드는 구조체/클래스/열거형은 뭐 위와 같이 대소 비교 연산을 사용하기 위해선

Comparable을 직접 채택하고 필요 시 구현도 해줘야겠다는 것을 말이죠! ^v^;;

또한 Equatable을 채택하고 있기 때문에 클래스의 경우 Equatable에 대한 구현이 필수라는 걸요 ^v^;;;;;

모른다면 프로토콜 3총사 다시 읽으셈

 

자, 그럼 어떻게 사용하나 봅시다 고고

 

 

 

 

2. 구조체/클래스/열거형에서 크기 비교 연산을 쓰는 방법

 

 

2-1. 구조체

 

지금껏 구조체는 프로토콜을 채택만 하고 구현하지 않아도,

충분히 사용히 가능했딴 말임??

 

 

struct PersonComparable {
    var name = ""
    var age = 0
}
 
let sodeul = Person.init(name: "sodeul", age: 28)
let clone = Person.init(name: "clone", age: 30)
 

 

 

이렇게 해주면 되겠지!!!!!

하겠지만 에러남 

 

 

 

 

...

배신이야

 

아쉽게도 Comparable 같은 경우, 구조체에서 Comparable을 채택하는 것만으로 사용할 수 없음

근데 생각을 해보면 당연하지 않음??

Equatable이나 Hashable 같은 경우, 따로 구현을 해주지 않으면

"모든 저장 프로퍼티"를 비교하거나 Hash하는 것으로 알아서 구현을 해줬단 말임

 

근데 Comparable 같은 경우는,

name이란 글자로 비교를 해야할지, age란 숫자로 비교를 해야할지,

혹은 그 둘 모두로 비교를 해야할지에 대해서 알 수 없기 떄문에

이때는 클래스가 그랬던 것 처럼 구조체도 프로토콜의 메서드를 직접 구현해주어야 함

 

근데 <, <=, >, >= 이 네개 언제 다 구현하고 앉아있나요??

라고 화가 나신다면 정상입니다

다행히 유도리 있는 Swift는 < 이 메서드 하나만 작성하면 됨 ㅎㅎㅎ

 

 

struct PersonComparable {
    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.age < rhs.age
    }
    
    var name = ""
    var age = 0
}
 
let sodeul = Person.init(name: "sodeul", age: 28)
let clone = Person.init(name: "clone", age: 30)
 
sodeul = clone           // false
sodeul <= clone          // true

 

 

이렇게!!! 하나만 구현 해도 다 사용할 수있고,

구현해놓은 것처럼 age를 통해 대소비교도 가능함 :)

 

 

 

2-2. 클래스

 

클래스는 사람이 한결같아서 참 좋아

늘 그랬듯이 채택 and 구현 해주시면 됨

 

 

import UIKit
 
class PersonComparable {
    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.age < rhs.age
    }
    
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
 
let sodeul = Person.init(name: "sodeul", age: 28)
let clone = Person.init(name: "clone", age: 30)

 

 

이렇게!!! 

근데 뭐라고???

 

 

 

 

 Equatable을 잊지 말라구-!

 

 

import UIKit
 
class PersonComparable {
    static func == (lhs: Person, rhs: Person) -> Bool {
        return lhs.name == rhs.name && lhs.age == rhs.age
    }
    
    static func < (lhs: Person, rhs: Person) -> Bool {
        return lhs.age < rhs.age
    }
    
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
 
let sodeul = Person.init(name: "sodeul", age: 28)
let clone = Person.init(name: "clone", age: 30)
 
sodeul > clone           // false
sodeul <= clone          // true

 

 

요롷게!

클래스에서 Comparable을 채택하고 싶다면

==, < 이렇게 두 개의 메서드를 모두 구현해주어야 함!!!

 

귀찮다 상속 필요 없으면 걍 구조체 쓰자

swift 구조체 장려하잖아 엉엉

 

 

 

2-3. 열거형

 

흐움.. 열거형의 경우 어느정도 조건이 있음

먼저, Swift 5.3 미만의 경우 Comparable을 채택 & 구현을 해줘야 함

 

 

enum NumberIntComparable {
    static func < (lhs: Number, rhs: Number) -> Bool {
        return lhs.rawValue < rhs.rawValue
    }
    
    case one, two, three
}
 
Number.one > Number.two     // false

 

 

이런 식으루!

만약 rawValue나 열거형이 생소하시다면 이 포스팅부터 보시길 ㅎㅎ;

쨌든 그건 그렇고 Swift 5.3이상부터로 보자면!!!

 

.. ㅈㅅ

내 playground swift 버전이 낮아서 이론만 적고 ㅌㅌ... 

알아서 테스트 해보시길..

 

 

1️⃣ (Swift 5.3+) 연관값이 없거나 / 연관값이 모두 Comparable을 채택하고 있는 경우

 

이 경우엔 ComParable을 "채택" 하는 것만으로도 사용이 가능함

 

 

2️⃣ (Swift 5.3+)연관값 중 하나라도 Comparable을 채택하지 않은 경우

 

이 경우엔 채택 뿐 아니라 < 메서드를 직접 구현 해줘야 한답니다

 

 

 

 

 

 

 

 

.

.

.

 

드디어 프로토콜 3총사를 끝냈네요 :)))

어려운 내용은 없었을 거라 생각 합니다!!!

다음 포스팅부턴 조금 어렵고 무서운 주제를 들고 오겠다!!!!

 

오타 및 피드백 대환영!



Calendar
«   2024/05   »
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
최근 댓글
Visits
Today
Yesterday