Hash란?
- 데이터를 관리, 유지하는 자료구조로 데이터들을 해시 함수를 통해 key로 분류하고, 그 key에 따라 value를 저장하는 형태를 뜻합니다.
- 즉, "Hash"는 데이터를 고유한 숫자 값으로 변환하는 과정 또는 그 결과를 의미합니다.
- 이 때 숫자 값은 "해시 값(hash value)"라고 합니다.
"Apple" 이라는 과일의 숫자 값으로 변환한다면?
let apple: String = "사과"
print(apple.hashValue)
// -7518292052611397302
위의 에서 나온 "-7518292052611397302" 값이 바로 해시 값이라고 합니다.
(이 때, 해시 값은 매번 달라집니다.)
그렇다면 왜 해시 값이 필요할까?
컴퓨터는 문자열이나 복잡한 데이터를 숫자로 변환하면 작업을 더 빠르고, 효율적으로 할 수 있게 됩니다.
숫자는 비교, 검색, 계산이 훨씬 빠르기 때문입니다.
해시의 특징
- 고유성 (Uniqueness):
- 이상적으로는 서로 다른 값은 서로 다른 해시 값을 가져야 합니다.
- 예: Alice → 12345, Bob → 67890
- 하지만 가끔 해시 충돌(hash collision)이 일어날 수 있습니다.. 이는 서로 다른 데이터가 같은 해시 값을 가지는 경우인데, 이 문제는 나중에 해결 방법을 다루갰습니다.
- 빠른 비교:
- 해시 값을 비교하는 게 원래 데이터를 직접 비교하는 것보다 훨씬 빠릅니다.
- 예를 들어, 책의 제목을 다 비교하는 대신 해시 값을 비교하면 효율적입니다.
- 짧은 길이:
- 아무리 데이터가 길어도 해시 값은 일정한 길이를 유지해줍니다.
- 예: 이름 Alice와 긴 문장 Once upon a time...을 해시로 바꾸면 둘 다 비슷한 길이의 숫자 값이 나옵니다.
Hashable 프로토콜이란?
스위프트에서 다음과 같은 상황에서 Hashable 프로토콜을 채택합니다.
- disctionary의 key의 타입으로 사용할 때
- set 타입으로 사용할 떄
왜냐하면, dictionary와 set은 array와 다르게 순서가 없어서 검색하기 위한 수단으로 사용할 수 있기 때문입니다.
Hashable 프로토콜이 구조체에서 하는 역할
구조체가 Hashable을 채택하면, 그 구조체의 인스턴스를 해시 값으로 변환할 수 있게 됩니다.
즉, Hashable을 채택한 덕분에 Section의 각 인스턴스는 고유한 해시 값을 가지게 되고, 이 해시 값은 Set, Dictionary와 같은 컬렉션에서 비교나 검색에 사용할 수 있게 됩니다.
struct Section: Decodable, Hashable {
let id: Int
let type: String
let title: String
let subtitle: String
let items: [App]
}
🔴 id와 Hashable은 별개의 개념입니다.
- sectionA.id와 Hashable의 해시 값은 다릅니다.
- id는 Section 안에 정의된 고유 식별자일 뿐이고, Hashable을 통해 만들어지는 해시 값은 Section의 전체 데이터를 기반으로 계산된 고유 값입니다.
- 즉, id는 프로그래머가 설계한 명시적인 고유 값,
해시 값은 Hashable 프로토콜이 정의한 계산된 고유 값입니다.
- 왜 id와 해시 값이 둘 다 필요한가?
- id는 우리가 직접 사용하려고 만든 속성으로. 이 값은 사람이 고유성을 관리하거나 특정 작업에 사용하기 위해 정의한 것입니다.
- 반면, Hashable의 해시 값은 Set이나 Dictionary 같은 컬렉션이 비교나 검색을 더 빠르게 할 수 있도록 만들어진 값입니다.
- 즉, id는 명시적 고유성, 해시 값은 성능 최적화를 위한 도구라고 보면 됩니다.
UICollectionViewDiffableDataSource 나
UICollectionViewCompositionalLayout 에서
Hashable이 중요한 이유?
1. Diffable DataSource가 데이터를 관리하는 방식
기존의 데이터와 새롭게 들어온 데이터를 비교해서, 달라진 부분만 업데이트하는 방식으로 작동합니다.
이 작업은 데이터의 비교와 고유성 판단이 중요합니다.
- id만으로도 고유성을 판단할 수 있지 않나?
- Hashable을 채택하면 단순히 id만 비교하는 게 아니라 구조체의 전체 값을 기준으로 고유성을 확인합니다.
- 예를 들어, Section 구조체 안의 title이나 items 같은 값도 비교 대상이 됩니다.
- Diffable DataSource는 Hashable 덕분에 모든 속성을 기반으로 데이터를 비교해 변경된 부분만 효율적으로 업데이트할 수 있어요.
- id만 비교하면, 같은 id를 가진 데이터가 일부 내용이 바뀌었을 때 이를 감지할 수 없겠죠.
2. 중복 체크와 검색을 위한 Hashable
Diffable DataSource는 데이터가 많아질수록 중복 체크와 검색을 효율적으로 해야 해요.
- 이때, Hashable을 통해 데이터의 고유성을 판단하고 중복을 제거할 수 있습니다.
- 내부적으로 Set 같은 자료구조를 사용할 수 있는데, 이 자료구조는 Hashable을 필요로 해요.
3. UI 업데이트 최적화를 위한 필요성
컬렉션 뷰의 데이터가 변경되면, 전체를 다시 그리는 대신 달라진 부분만 업데이트하는 게 성능 면에서 훨씬 효율적입니다.
- Diffable DataSource는 Hashable을 통해 변경된 데이터만 탐지하고, 해당 셀만 업데이트합니다.
struct Item: Hashable {
let id: Int
let name: String
}
let oldItems = [
Item(id: 1, name: "Apple"),
Item(id: 2, name: "Banana")
]
let newItems = [
Item(id: 1, name: "Apple"),
Item(id: 2, name: "Orange") // Banana가 Orange로 바뀜
]
// Diffable DataSource는 oldItems와 newItems를 비교해
// "id가 2인 데이터가 바뀌었다"는 것을 감지
4. Hashable을 채택하지 않으면?
Hashable을 채택하지 않으면 Diffable DataSource나 Compositional Layout 같은 구조가 제대로 동작하지 않습니다
- 이들은 데이터의 비교, 검색, 중복 제거를 위해 내부적으로 Set이나 Dictionary 같은 자료구조를 사용하는데, 이런 자료구조는 Hashable을 필요로 합니다.
- 즉, Hashable은 Diffable DataSource가 데이터를 효율적으로 관리할 수 있는 핵심 도구입니다.
'정보' 카테고리의 다른 글
디자인 패턴 - 싱글톤 패턴 (0) | 2024.12.17 |
---|---|
Hashable과 Equatable은 밀접한 관계 (0) | 2024.12.16 |
Static Dispatch vs Dynamic Dispatch (1) | 2024.12.13 |
클래스와 구조체가 섞여 있을 때... (0) | 2024.12.13 |
DispatchQueue.main.async와 DispatchQueue.main.sync의 차이점은 무엇인가요? (0) | 2024.12.13 |