๐๐ป ์ด์ ํฌ์คํธ์์ randomuser api ๋ฐ์ดํฐ๋ฅผ struct๊ตฌ์กฐ๋ก ๋ณํํด์ ์ฑ์์ ๋ฐ์ดํฐ๋ฅผ ํํํ๋๋ก ๊ตฌํํด๋ดค์ต๋๋ค.
In the previous post, I converted the randomuser API data into a struct structure and implemented it to represent the data in the app.
์ด struct๊ตฌ์กฐ์์ ๋ง์ด ์ฌ์ฉ๋๋ ํ๋กํ ์ฝ์ด Identifiable,Equatable,Hashable์
๋๋ค.
The protocols that are widely used in this struct structure are Identifiable, Equatable, and Hashable.
https://www.freelifemakers.org/wordpress/index.php/2025/12/25/swift-infinitescreoo-refresh-loading/
๐๐ป ์๋๋ ์ด ํ๋กํ ์ฝ๋ค์ ๊ธฐ๋ฅ์ ์ดํดํ๊ธฐ ์ํ ๋ํ์ธ ๊ธฐ๋ฅ๋ง ๊ตฌํํ์ต๋๋ค.
Below, only representative functions are implemented to help you understand the functionality of these protocols.
๐๐ปIdentifiable , Hashable
Swift์์ ์์ ์์ ์ฒ๋ผ api๋ฐ์ดํฐ๋ฅผ struct๊ตฌ์กฐ๋ก ๋ณํํ์ฌ ์ฑ์์ ์ฌ์ฉํ๋ ๊ตฌ์กฐ๋ฑ์์ Identifiable,Equatable,Hashable์ด ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
In Swift, Identifiable, Equatable, and Hashable are widely used in structures used in apps by converting API data into struct structures, as in the example above.
struct๋ ํด๋์ค๋ฅผ ์ฌ์ฉ ํ ๊ฒฝ์ฐ ์ธ์คํด์ค(๊ฐ์ฒด)๋ฅผ ์์ฑํ๊ฒ ๋ฉ๋๋ค.
When using a struct or class, an instance (object) is created.
์ด ๋ ์๋์ฒ๋ผ ๋์ผํ ๊ฐ์ ๋์
ํ์ฌ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ฉด ๋ฐ๋ณต๋ฌธ์์ ์ถ๋ ฅ์ ๋ฐ๋ณต๋ฌธ ๋ด์์ ๊ฐ ์ธ์คํด์ค๋ฅผ ๊ตฌ๋ถ์ง๊ธฐ๊ฐ ํ๋ค์ด์ง๋๋ค.
At this time, if you create an instance by substituting the same value as below, it becomes difficult to distinguish each instance within the loop when outputting it.
๊ทธ๋์ Identifiable์ด๋,Hashable ํ๋กํ ์ฝ์ ์ฌ์ฉํด์ ๊ฐ ์ธ์คํด์ค๋ฅผ ๊ตฌ๋ถ์ง์ ์ ์๊ฒ ํด์ค๋๋ค.
So, we can use the Identifiable or Hashable protocol to distinguish each instance.
Identifiable์ ์ฌ์ฉ์๊ฐ ์ง์ id๋ฅผ ์์ฑํด์ ๊ตฌ๋ถ ์ง๋ ๋ฐฉ๋ฒ์ด๊ณ Hashable ํ๋กํ ์ฝ์ ์ฌ์ฉํ๋ฉด ์๋์ ์ผ๋ก ๋ด๋ถ์ hash๊ฐ์ด ์์ฑ๋์ด ์ธ์คํด์ค๋ฅผ ๊ตฌ๋ถ์ง์ ์ ์๊ฒ ํด์ค๋๋ค.
Identifiable is a method in which the user creates an id to distinguish them, and if the Hashable protocol is used, a hash value is automatically generated internally to distinguish instances.
์ธ์คํด์ค๋ฅผ ๊ตฌ๋ถ์ง์ด์ผํ๋ ์ด์ ๋ ๋์ค์ ๋ฐ์ดํฐ์ ์ถ๊ฐ ์ญ์ ๋ณ๊ฒฝ์ด ๋ฐ์ํ ๋ ํ์ํ๊ธฐ ๋๋ฌธ์
๋๋ค.
The reason we need to distinguish between instances is because we need to do additional deletions and changes to the data later.
โ๏ธ Identifiable์ ์ด๋ ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
Identifiable is used like this:
Identifiable์ด ๋ง์กฑ๋๋ฉด SwiftUI์ List, ForEach ๋ฑ์์ ๋ฐ๋ก ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.
Once Identifiable is satisfied, it can be used directly in SwiftUI’s List, ForEach, etc.
struct Person: Identifiable {
let id = UUID() // ๊ณ ์ UUID ์๋ ์์ฑ
let name: String
let age: Int
}
List,ForEach์์ ์ฌ์ฉ๋ฐฉ๋ฒ
How to use List, ForEach
import SwiftUI
struct Person: Identifiable {
// ๊ณ ์ UUID ์๋ ์์ฑ / Automatically generate unique UUID
let id = UUID()
let name: String
let age: Int
}
struct PersonListView: View {
let people: [Person] = [
Person(name: "Alice", age: 30),
Person(name: "Bob", age: 35),
Person(name: "Charlie", age: 25),
Person(name: "Diana", age: 28)
]
var body: some View {
List(people) { person in
HStack {
Text(person.name)
.font(.headline)
Spacer()
Text("\(person.age) years old")
.foregroundColor(.secondary)
}
}
.navigationTitle("People List")
}
}
โ๏ธ Hashable์ ์ด๋ ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
This is how Hashable is used:
Dictionary์ ํค๋ก ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋๋ค.
Allows you to use it as a key in a dictionary.
struct Product: Hashable {
let productID: Int
let name: String
}
Hashable์ด ์ ์ฉ๋ struct๋ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
A struct with Hashable applied can be used as follows:
// prices๋์
๋๋ฆฌ๋ฅผ Product์ Doubleํ์
์ผ๋ก ์์ฑ
// Create a prices dictionary with Product and Double types
var prices: [Product: Double] = [:]
// ๊ฐ์ด ๊ฐ์ ์ธ์คํด์ค1 / Instance 1 with the same value
let iPhone = Product(productID: 1, name: "iPhone 15")
let iPad = Product(productID: 2, name: "iPad Pro")
// 1500000์ ๊ฐ์๊ฐ, ์ธ๋์ค์ฝ์ด๋ ๋ฌด์๋จ.
// Same value as 1500000, underscores are ignored.
prices[iPhone] = 1_500_000
prices[iPad] = 1_200_000
// ๊ฐ์ ์ ํ์ผ๋ก ๊ฐ๊ฒฉ ์กฐํ / Check price for the same product
// ๊ฐ์ด ๊ฐ์ ์ธ์คํด์ค2 / Instance 2 with the same value
let sameiPhone = Product(productID: 1, name: "iPhone 15")
print(prices[sameiPhone] ?? 0) // 1500000.0
// ๊ฐ๊ฒฉ ์
๋ฐ์ดํธ / price update
prices[sameiPhone] = 1_450_000
print(prices[iPhone]!) // 1450000.0
๐๐ป Equatable
โ๏ธ ์์ฑ๋ ์ธ์คํด์ค(๊ฐ์ฒด)์ ๋ด์ฉ(๊ฐ)์ ๋น๊ตํ๊ธฐ ์ํด์ ์ฌ์ฉ๋๋ ํ๋กํ ์ฝ์
๋๋ค.
This is a protocol used to compare the contents (values) of created instances (objects).
โ๏ธ Equatable์ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์ฉํฉ๋๋ค.
Equatable is used like this:
struct Person: Equatable {
let name: String
let age: Int
let email: String
}
let p1 = Person(name: "๊น์ฒ ์", age: 30, email: "kim@example.com")
let p2 = Person(name: "๊น์ฒ ์", age: 30, email: "kim@example.com")
print(p1 == p2) // true โ Swift๊ฐ ์๋์ผ๋ก ๋ชจ๋ ํ๋กํผํฐ ๋น๊ตํด์ค
โ๏ธ Swift ์ด๊ธฐ ๋ฒ์ (์: Swift 3~4.0) ์คํ์ผ๋ก, Equatable์ ์ง์ ๊ตฌํํ ํํ์
๋๋ค.
This is a direct implementation of Equatable in the style of early Swift versions (e.g. Swift 3-4.0).
โ๏ธ ์๋๋ static func == ์ด๋ ๊ฒ == ์ด๋ฆ์ธ ํจ์๋ฅผ ๋ง๋ค์ด ์ฃผ๊ณ == ์ด ์ฐ์ฐ์๊ฐ ํธ์ถ๋๋ฉด
static func == ์ด ํจ์๊ฐ ํธ์ถ๋๋ ํํ์
๋๋ค.
Originally, a function named == was created like this: static func == , and when the == operator was called,
static func == This function was called.
โ๏ธ ํ์ง๋ง swift4.1๋ถํฐ๋ Equtableํ๋กํ ์ฝ์ ์ฌ์ฉํ๊ณ == ์ฐ์ฐ์๋ง ํธ์ถํ๋ฉด swift๊ฐ ์๋์ผ๋ก ํจ์๋ฅผ ๋ง๋ค์ด ์ค๋๋ค.
However, starting from Swift 4.1, if you use the Equtable protocol and only call the == operator, Swift will automatically create a function.
struct Person: Equatable {
let name: String
let age: Int
let email: String
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.name == rhs.name && lhs.age == rhs.age
// email์ ๋น๊ต์ ํฌํจ ์ ๋จ
}
}
๐๐ป ๊ฒฐ๋ก ์ identifiable๊ณผ Hashable์ ๋์ผํ ๊ฐ์ ๊ฐ์ง ์ธ์คํด์ค๋ฅผ ๋ฐ๋ณต๋ฌธ์ด๋ ์ฝ๋ ์
์์ ๊ตฌ๋ถ์ง๊ธฐ ์ํด์ ์ฌ์ฉ๋๋ ๊ฑฐ๊ณ Equatable์ ์ธ์คํด์ค์ ๊ฐ์ ์ฝ๊ฒ ๋น๊ตํ ์์๊ฒ ํด์ฃผ๋ ํ๋กํ ์ฝ ์
๋๋ค.
In conclusion, identifiable and Hashable are used to distinguish instances with the same value in loops or collections, and Equatable is a protocol that allows for easy comparison of instance values.