관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] OptionSet에서 시프트 연산자를 사용하는 이유(Shift Operator) 본문

iOS 응용 (swift)

[iOS - swift] OptionSet에서 시프트 연산자를 사용하는 이유(Shift Operator)

jake-kim 2024. 9. 25. 01:18

OptionSet 개념

  • OptionSet은 옵션이 있는 Set 자료구조이며, 옵션들을 마치 enum-case처럼 다룰 수 있고 set의 대표적인 연산자 insert, remove, contains, intersection 를 쓸 수 있는 자료구조

ex) UserSetting에 관한 플래그를 관리하는 OptionSet

struct UserSettingsFlags: OptionSet {
    let rawValue: Int
    
    static let darkMode                = UserSettingsFlags(rawValue: 1 << 0)
    static let notifications           = UserSettingsFlags(rawValue: 1 << 1)
    static let locationServices        = UserSettingsFlags(rawValue: 1 << 2)
    static let autoUpdate              = UserSettingsFlags(rawValue: 1 << 3)
    static let privacyMode             = UserSettingsFlags(rawValue: 1 << 4)
    static let sound                   = UserSettingsFlags(rawValue: 1 << 5)
    static let vibration               = UserSettingsFlags(rawValue: 1 << 6)
    static let emailUpdates            = UserSettingsFlags(rawValue: 1 << 7)
    static let twoFactorAuthentication = UserSettingsFlags(rawValue: 1 << 8)

    static let all: UserSettingsFlags = [
        .darkMode,
        .notifications,
        .locationServices,
        .autoUpdate,
        .privacyMode,
        .sound,
        .vibration,
        .emailUpdates,
        .twoFactorAuthentication
    ]
}

OptionSet에서 rawValue를 bit로 표현하는 이유?

  • 일반적으로 OptionSete에서는 rawValue를 보면 모두 shift연산자를 통해 표현
static let darkMode                = UserSettingsFlags(rawValue: 1 << 0)  // 0000 0001 (1)
static let notifications           = UserSettingsFlags(rawValue: 1 << 1)  // 0000 0010 (2)
static let locationServices        = UserSettingsFlags(rawValue: 1 << 2)  // 0000 0100 (4)
static let autoUpdate              = UserSettingsFlags(rawValue: 1 << 3)  // 0000 1000 (8)
static let privacyMode             = UserSettingsFlags(rawValue: 1 << 4)  // 0001 0000 (16)
static let sound                   = UserSettingsFlags(rawValue: 1 << 5)  // 0010 0000 (32)
static let vibration               = UserSettingsFlags(rawValue: 1 << 6)  // 0100 0000 (64)
static let emailUpdates            = UserSettingsFlags(rawValue: 1 << 7)  // 1000 0000 (128)
static let twoFactorAuthentication = UserSettingsFlags(rawValue: 1 << 8)  // 0001 0000 0000 (256)

 

* bit로 표현하는 이유?

  • 1. 비트 OR, AND 연산을 통해 충돌 없이 다중 상태 표현하기가 용이
let option1 = 1 << 4   // 0001 0000 (16)
let option2 = 1 << 5   // 0010 0000 (32)

let combined = option1 | option2   // OR 연산: 0011 0000 (48)
  • 2. 메모리 효율성
    • bit대신에 Bool타입 flag를 사용할 경우 아래와 같이 8개가 있을 때, Bool하나에 1바이트가 필요하므로 총 8바이트가 필요
    • 만약 bit로 표현하면 1바이트 필요
// 각각의 상태를 Bool로 관리할 경우
struct Settings {
    var flag1: Bool = false
    var flag2: Bool = false
    var flag3: Bool = false
    var flag4: Bool = false
    var flag5: Bool = false
    var flag6: Bool = false
    var flag7: Bool = false
    var flag8: Bool = false
}
  • 3. 비트 연산은 하드웨어적으로 매우 빠른 연산

* 읽어보면 좋은 관련 글: OptionSet으로 flag 리펙토링하기 (플래그 관리, Bool대신 bit 사용하기)

 

* 참고

- https://developer.apple.com/documentation/swift/optionset

Comments