본문 바로가기

정보

해시란? Hash, Hashable

Hash란?

  • 데이터를 관리, 유지하는 자료구조로 데이터들을 해시 함수를 통해 key로 분류하고, 그 key에 따라 value를 저장하는 형태를 뜻합니다.
  • 즉, "Hash"는 데이터를 고유한 숫자 값으로 변환하는 과정 또는 그 결과를 의미합니다. 
  • 이 때 숫자 값은 "해시 값(hash value)"라고 합니다. 

"Apple" 이라는 과일의 숫자 값으로 변환한다면?

let apple: String = "사과"
print(apple.hashValue)

// -7518292052611397302

 

위의 에서 나온 "-7518292052611397302" 값이 바로 해시 값이라고 합니다. 

(이 때, 해시 값은 매번 달라집니다.)

 

그렇다면 왜 해시 값이 필요할까?

컴퓨터는 문자열이나 복잡한 데이터를 숫자로 변환하면 작업을 더 빠르고, 효율적으로 할 수 있게 됩니다. 

숫자는 비교, 검색, 계산이 훨씬 빠르기 때문입니다.

 

해시의 특징

  1. 고유성 (Uniqueness):
    • 이상적으로는 서로 다른 값은 서로 다른 해시 값을 가져야 합니다.
    • 예: Alice → 12345, Bob → 67890
    • 하지만 가끔 해시 충돌(hash collision)이 일어날 수 있습니다.. 이는 서로 다른 데이터가 같은 해시 값을 가지는 경우인데, 이 문제는 나중에 해결 방법을 다루갰습니다.
  2. 빠른 비교:
    • 해시 값을 비교하는 게 원래 데이터를 직접 비교하는 것보다 훨씬 빠릅니다.
    • 예를 들어, 책의 제목을 다 비교하는 대신 해시 값을 비교하면 효율적입니다.
  3. 짧은 길이:
    • 아무리 데이터가 길어도 해시 값은 일정한 길이를 유지해줍니다.
    • 예: 이름 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은 별개의 개념입니다.

  1. sectionA.id와 Hashable의 해시 값은 다릅니다.
    • id는 Section 안에 정의된 고유 식별자일 뿐이고, Hashable을 통해 만들어지는 해시 값은 Section의 전체 데이터를 기반으로 계산된 고유 값입니다.
    • 즉, id는 프로그래머가 설계한 명시적인 고유 값,
      해시 값은 Hashable 프로토콜이 정의한 계산된 고유 값입니다.
  2. 왜 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 DataSourceHashable을 통해 변경된 데이터만 탐지하고, 해당 셀만 업데이트합니다.
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가 데이터를 효율적으로 관리할 수 있는 핵심 도구입니다.