Swift์๋ ์ฌ๋ฌ ๊ฐ์ง ํ๋กํ ์ฝ์ด ์กด์ฌํ์ฃ !
๊ทธ์ค์์๋ Equatable, Comparable, Hashable์ ๊ฐ์ฅ ์์ฃผ ์ฌ์ฉ๋๋ ๊ธฐ๋ณธ ํ๋กํ ์ฝ์ ๋๋ค.
๋ชจ๋ธ ๋น๊ต, ์ ๋ ฌ, ์ค๋ณต ์ ๊ฑฐ ๋ฑ ์ค๋ฌด์์๋ ์์ฃผ ๋ฑ์ฅํ๋ ์ค์ํ ๊ฐ๋ ์ธ๋ฐ์.
๊ทธ๋ผ ์ฐจ๊ทผ์ฐจ๊ทผ ํ๋์ฉ ์์๋ด ์๋ค!
๐ Equatable
Equatable์ ๋ ๊ฐ์ด ๊ฐ์์ง ๋น๊ตํ ์ ์๋ ํ์ ์ ์ ์ํ๋ ํ๋กํ ์ฝ์ ๋๋ค.
๊ณต์ ๋ฌธ์๋ฅผ ์ดํด๋ณด๋ฉด…
“Values of types that conform to Equatable can be checked for equality using the == operator.”
์ฆ, Equatable์ ์ฑํํ๋ฉด == ์ฐ์ฐ์๋ฅผ ํตํด ๋ ์ธ์คํด์ค๊ฐ ๊ฐ์์ง ๋น๊ตํ ์ ์์ต๋๋ค.
Equatable์ ํน์ง
- == ์ != ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ๊ตฌ์กฐ์ฒด๋ ์ด๊ฑฐํ์ฒ๋ผ ๋จ์ํ ํ์ ์ Swift๊ฐ ์๋์ผ๋ก Equatable์ ๊ตฌํํฉ๋๋ค.
Equatable์ ๋ค์ ๋ฐฐ์ธ Comparable๊ณผ Hashable์ ๊ธฐ๋ฐ์ด ๋ฉ๋๋ค!
๊ทธ๋ ๋ค๋ฉด Equatable์ ์ธ์ ์ฌ์ฉํ ๊น์?
Equatable์ ๋ ๊ฐ์ด ์๋ก ๋์ผํ์ง ๋น๊ตํด์ผ ํ ๋ ์ฌ์ฉํ๋๋ฐ์.
์๋ฅผ ๋ค์ด, ํน์ ์ผ๊ธฐ๊ฐ ๊ฐ์ ์ผ๊ธฐ์ธ์ง, ํน์ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ๋์ผํ ๋ฐ์ดํฐ์ธ์ง ํ๋จํ ๋ ํ์ฉํ ์ ์์ต๋๋ค.
๋ํ ๋ฐฐ์ด ๋ด์์ ์ค๋ณต๋ ์์๋ฅผ ์ ๊ฑฐํ๊ฑฐ๋, ํน์ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ๋๋ ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
์์
struct DiaryEntry: Equatable {
let id: Int
let title: String
}
let entry1 = DiaryEntry(id: 1, title: "์ฒซ ์ผ๊ธฐ")
let entry2 = DiaryEntry(id: 1, title: "์ฒซ ์ผ๊ธฐ")
print(entry1 == entry2) // true
์ด์ฒ๋ผ id์ title์ด ๋ชจ๋ ๊ฐ์ผ๋ฉด true๋ฅผ ๋ฐํํฉ๋๋ค.
Swift๊ฐ ์๋์ผ๋ก == ํจ์๋ฅผ ์์ฑํ๋ฏ๋ก, ์ง์ ๊ตฌํํ์ง ์์๋ ๋ฉ๋๋ค.
์ง์ ๋น๊ต ๊ธฐ์ค์ ์ ํ๊ณ ์ถ๋ค๋ฉด ์๋์ฒ๋ผ ๊ตฌํํ ์ ์์ต๋๋ค.
struct DiaryEntry: Equatable {
let id: Int
let title: String
static func == (lhs: DiaryEntry, rhs: DiaryEntry) -> Bool {
return lhs.id == rhs.id
}
}
์ฃผ์ํ ์
- a == a, a == b ⇒ b == a, a == b && b == c ⇒ a == c์ฒ๋ผ ๋ ผ๋ฆฌ์ ์ผ๋ก ์ผ๊ด์ฑ์ด ์ ์ง๋์ด์ผ ํฉ๋๋ค.
- ๊ธฐ๋ณธ ํ์ (Int, String ๋ฑ)์ ์ด๋ฏธ Equatable์ ์ฑํํ๊ณ ์์ต๋๋ค.
- ๋จ์ ๋น๊ต ์ด์์ ๊ธฐ๋ฅ(์ ๋ ฌ, ๊ฒ์ ๋ฑ)์ด ํ์ํ๋ค๋ฉด Comparable ๋๋ Hashable์ ํจ๊ป ๊ณ ๋ คํฉ๋๋ค.
๐ Comparable
Comparable์ ๊ฐ ์ฌ์ด์ ์์๋ฅผ ๋น๊ตํ ์ ์๋๋ก ํด์ฃผ๋ ํ๋กํ ์ฝ์ ๋๋ค.
“Comparable types can be compared using relational operators like <, <=, >, >=.”
์ฆ, <, >, <=, >= ๊ฐ์ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Comparable์ ํน์ง
- Comparable์ Equatable์ ์์ํ๊ณ ์์ต๋๋ค.
- < ๋ง ์ง์ ๊ตฌํํ๋ฉด ๋๋จธ์ง ์ฐ์ฐ์(<=, >, >=)๋ Swift๊ฐ ์๋์ผ๋ก ์์ฑํฉ๋๋ค.
- sorted(), min(), max() ๋ฑ๊ณผ ํจ๊ป ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ <๋ ์ง์ ๊ตฌํํด์ผ ํ ๊น์?
๊ทธ ์ด์ ๋ ํ์ ๋ง๋ค ‘์๋ค’์ ๊ธฐ์ค์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋๋ค!
์๋ฅผ ๋ค์ด, ๋ ์ง๋ฅผ ๋น๊ตํ ๋๋ ๋ ์ด์ ์ ๋ ์ง๊ฐ ์๋ค๊ณ ํ๋จํด์ผ ํ๊ณ , ์ ์๋ฅผ ๋น๊ตํ ๋๋ ๋ ๋ฎ์ ์ ์๊ฐ ์๋ค๊ณ ๋ณผ ์ ์์ต๋๋ค.
์ด์ฒ๋ผ “๋ฌด์์ด ๋ ์์๊ฐ”์ ๊ธฐ์ค์ ํ์ ๋ง๋ค ๋ค๋ฅด๊ธฐ ๋๋ฌธ์, Swift๋ ๊ฐ๋ฐ์๊ฐ ์ง์ < ์ฐ์ฐ์ ์๋ฏธ๋ฅผ ์ ์ํ๋๋ก ์๊ตฌํ๋ ๊ฑฐ์ฃ .
Comparable์ ๋ ์ง, ์ ์, ์์์ฒ๋ผ ์์๋ฅผ ์ ํ ์ ์๋ ๊ฐ์ ๋น๊ตํ ๋ ์ฌ์ฉํฉ๋๋ค.
์๋ฅผ ๋ค์ด “์ค๋๋ ๊ธ๋ถํฐ ์ ๋ ฌํ๊ธฐ” ๋๋ “์ข์์๊ฐ ๋ง์ ์์ผ๋ก ์ ๋ ฌํ๊ธฐ” ๋ฑ์ ์ํฉ์์ ํ์ฉํ ์ ์๊ฒ ์ฃ ?
์์
struct DiaryEntry: Comparable {
let id: Int
let date: Date
static func < (lhs: DiaryEntry, rhs: DiaryEntry) -> Bool {
return lhs.date < rhs.date
}
}
let entries = [
DiaryEntry(id: 1, date: Date(timeIntervalSinceNow: 3600)),
DiaryEntry(id: 2, date: Date())
]
let sorted = entries.sorted()
print(sorted.map { $0.id }) // [2, 1] — ์ค๋๋ ์ผ๊ธฐ๋ถํฐ ์ ๋ ฌ๋ฉ๋๋ค.
ํด๋น ์ฝ๋๋ ๋ ์ง๋ฅผ ๊ธฐ์ค์ผ๋ก < ์ฐ์ฐ์ ์ ์ํ๊ธฐ ๋๋ฌธ์, ์ ๋ ฌ ์ ์๋์ผ๋ก “์ด์ ๋ ์ง → ์ดํ ๋ ์ง” ์์๋ก ์ ๋ ฌ๋ฉ๋๋ค.
์ฃผ์ํ ์
- a < b๋ผ๋ฉด ๋ฐ๋์ a != b์ฌ์ผ ํฉ๋๋ค.
- ์ ๋ ฌ ๊ธฐ์ค์ด ๋ฐ๋๋ฉด ์ฝ๋ ์ ๋ฐ์ ๊ฒฐ๊ณผ๋ ๋ฌ๋ผ์ง ์ ์์ผ๋ฏ๋ก, ์ผ๊ด๋ ๊ธฐ์ค์ ์ ์งํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- Comparable์ ์ฑํํ๋ฉด Equatable ๊ธฐ๋ฅ๋ ์๋์ผ๋ก ํฌํจ๋ฉ๋๋ค.
๐ Hashable
Hashable์ ๊ฐ์ฒด๋ฅผ ๊ณ ์ ํ ํด์๊ฐ(hash value) ์ผ๋ก ๋ณํํ ์ ์๊ฒ ํด์ฃผ๋ ํ๋กํ ์ฝ์ ๋๋ค.
“A type that conforms to Hashable can be used as a key in a dictionary or as an element in a set.”
์ฆ, Hashable์ ์ฑํํ ํ์ ์ Dictionary์ ํค๋ Set์ ์์๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
Hashable์ ํน์ง
- hash(into:) ๋ฉ์๋๋ฅผ ํตํด ๊ณ ์ ํ ํด์ ๊ฐ์ ์์ฑํฉ๋๋ค.
- ๊ฐ์ ๊ฐ์ฒด๋ผ๋ฉด ํญ์ ๊ฐ์ ํด์ ๊ฐ์ ๊ฐ์ ธ์ผ ํฉ๋๋ค.
- ๊ตฌ์กฐ์ฒด๋ ์ด๊ฑฐํ์ ๊ฒฝ์ฐ ๋๋ถ๋ถ ์๋์ผ๋ก Hashable์ด ๊ตฌํ๋ฉ๋๋ค.
Hashable์ Dictionary์ ํค๋ก ์ปค์คํ ํ์ ์ ์ฌ์ฉํด์ผ ํ ๋, ์ค๋ณต๋์ง ์๋ Set ์ปฌ๋ ์ ์ ๋ง๋ค ๋,
๋๋ ๊ณ ์ ์๋ณ์๋ฅผ ๊ฐ์ง ๊ฐ์ฒด๋ฅผ ํจ์จ์ ์ผ๋ก ๋น๊ตํ๊ฑฐ๋ ๊ด๋ฆฌํด์ผ ํ ๋ ์ฌ์ฉํฉ๋๋ค.
์์
struct Topic: Hashable {
let id: UUID
let name: String
}
var topicSet: Set<Topic> = []
let topicA = Topic(id: UUID(), name: "ํ์ด๋ง๊ตฌ์ผ ์ผ๊ธฐ")
let topicB = Topic(id: UUID(), name: "์ด๋ก์ฌ๊ณผ๋ฐ ์คํฐ๋")
topicSet.insert(topicA)
topicSet.insert(topicB)
print(topicSet.contains(topicA)) // true
์๋์ฒ๋ผ ์ง์ ํด์ ํจ์๋ฅผ ๊ตฌํํ ์๋ ์์ต๋๋ค.
struct Topic: Hashable {
let id: UUID
let name: String
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(name)
}
}
์ฃผ์ํ ์
- == ๋น๊ต์ ์ฌ์ฉํ ํ๋กํผํฐ์ hash(into:)์์ ์ฌ์ฉํ๋ ํ๋กํผํฐ๋ ๋์ผํด์ผ ํฉ๋๋ค.
- ํด์๊ฐ์ด ๊ฐ๋ค๊ณ ํด์ ํญ์ ๊ฐ์ ๊ฐ์ฒด์ธ ๊ฒ์ ์๋๋๋ค(์ถฉ๋ ๊ฐ๋ฅ์ฑ ์กด์ฌ).
- ๋จ์ํ ๊ตฌ์กฐ์ฒด๋ผ๋ id๋ name์ฒ๋ผ ๊ณ ์ ์๋ณ์๊ฐ ์๋ค๋ฉด ์๋์ผ๋ก hash(into:)๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ์์ ํฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก ๊ฐ ํ๋กํ ์ฝ์ ๋น๊ตํด๋ณด๋ฉด์ ์ ๋ฆฌํด๋ด ์๋ค!
| ํ๋กํ ์ฝ | ๋ชฉ์ | ํต์ฌ ์ฐ์ฐ์/๋ฉ์๋ | ์ฃผ์ ์ฌ์ฉ์ฒ |
| Equatable | ๋ ๊ฐ์ด ๊ฐ์์ง ๋น๊ต | ==, != | ๊ฐ ๋น๊ต, ์ค๋ณต ์ ๊ฑฐ |
| Comparable | ์์๋ฅผ ๋น๊ต | <, >, <=, >= | ์ ๋ ฌ, ์์ ๋งค๊น |
| Hashable | ๊ฐ์ ํด์ํ | hash(into:), == | Dictionary ํค, Set ์์ |
'๐ถ๐ข๐ฆ > ๐ iOS ๊ฐ๋ ํธ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [iOS / Swift] Codable & CodingKeys (0) | 2025.11.11 |
|---|---|
| [iOS / Swift] ํ ์ด๋ธ๋ทฐ์ ์ปฌ๋ ์ ๋ทฐ์ ๊ฐฑ์ ๋ฉ์๋ (0) | 2025.11.05 |
| [iOS / Swift] Enum์ด๋? (2) | 2025.11.04 |
| [iOS / Swift] Optional์ด๋? (1) | 2025.10.16 |
| [iOS / Swift] ์๋ช ์ฃผ๊ธฐ(Life Cycle)๋? (0) | 2025.10.16 |