[ios] Swift에서 NS_OPTIONS 스타일 비트 마스크 열거를 만드는 방법은 무엇입니까?

C API와의 상호 작용에 대한 Apple의 설명서에서 C NS_ENUM스타일 열거를 Swift 열거로 가져 오는 방법을 설명합니다 . 이것은 의미가 있으며 Swift의 열거 형은 다음과 같이 쉽게 제공됩니다.enum 값 유형 자체 작성 방법을 쉽게 볼 수 있습니다.

아래에 NS_OPTIONS표시된 C 스타일 옵션 에 대해 다음과 같이 말합니다 .

Swift는 NS_OPTIONS매크로 로 표시된 옵션도 가져옵니다 . 옵션은 수입 열거에 유사하게 동작하는 반면, 옵션은 다음과 같은 몇 가지 비트 연산을 지원할 수 &, |~. Objective-C에서 상수 0 ( 0)으로 설정된 빈 옵션을 나타냅니다 . Swift에서는 nil옵션이 없음을 나타내는 데 사용 하십시오.

optionsSwift에 값 유형 이없는 경우 C 스타일 옵션 변수를 작성하여 어떻게 작업 할 수 있습니까?



답변

스위프트 3.0

Swift 2.0과 거의 동일합니다. OptionSetType의 이름이 OptionSet으로 바뀌 었으며 열거 형은 규칙에 따라 소문자로 작성됩니다.

struct MyOptions : OptionSet {
    let rawValue: Int

    static let firstOption  = MyOptions(rawValue: 1 << 0)
    static let secondOption = MyOptions(rawValue: 1 << 1)
    static let thirdOption  = MyOptions(rawValue: 1 << 2)
}

none옵션 을 제공하는 대신 Swift 3 권장 사항은 단순히 빈 배열 리터럴을 사용하는 것입니다.

let noOptions: MyOptions = []

다른 사용법 :

let singleOption = MyOptions.firstOption
let multipleOptions: MyOptions = [.firstOption, .secondOption]
if multipleOptions.contains(.secondOption) {
    print("multipleOptions has SecondOption")
}
let allOptions = MyOptions(rawValue: 7)
if allOptions.contains(.thirdOption) {
    print("allOptions has ThirdOption")
}

스위프트 2.0

Swift 2.0에서 프로토콜 확장은이를위한 보일러 플레이트의 대부분을 처리하며, 이제는이를 준수하는 구조체로 가져옵니다 OptionSetType. ( RawOptionSetTypeSwift 2 베타 2부터 사라졌습니다.) 선언이 훨씬 간단합니다.

struct MyOptions : OptionSetType {
    let rawValue: Int

    static let None         = MyOptions(rawValue: 0)
    static let FirstOption  = MyOptions(rawValue: 1 << 0)
    static let SecondOption = MyOptions(rawValue: 1 << 1)
    static let ThirdOption  = MyOptions(rawValue: 1 << 2)
}

이제 다음과 함께 세트 기반 시맨틱을 사용할 수 있습니다 MyOptions.

let singleOption = MyOptions.FirstOption
let multipleOptions: MyOptions = [.FirstOption, .SecondOption]
if multipleOptions.contains(.SecondOption) {
    print("multipleOptions has SecondOption")
}
let allOptions = MyOptions(rawValue: 7)
if allOptions.contains(.ThirdOption) {
    print("allOptions has ThirdOption")
}

스위프트 1.2

(스위프트에 의해 수입 된 목표 – C 옵션을 보면 UIViewAutoresizing예를 들어,), 우리는 옵션이로 선언 된 것을 볼 수 있습니다 struct해당 프로토콜을 준수 RawOptionSetType차례에 부합 함을 선언에서에 _RawOptionSetType, Equatable, RawRepresentable, BitwiseOperationsType,와 NilLiteralConvertible. 우리는 다음과 같이 우리 자신을 만들 수 있습니다 :

struct MyOptions : RawOptionSetType {
    typealias RawValue = UInt
    private var value: UInt = 0
    init(_ value: UInt) { self.value = value }
    init(rawValue value: UInt) { self.value = value }
    init(nilLiteral: ()) { self.value = 0 }
    static var allZeros: MyOptions { return self(0) }
    static func fromMask(raw: UInt) -> MyOptions { return self(raw) }
    var rawValue: UInt { return self.value }

    static var None: MyOptions { return self(0) }
    static var FirstOption: MyOptions   { return self(1 << 0) }
    static var SecondOption: MyOptions  { return self(1 << 1) }
    static var ThirdOption: MyOptions   { return self(1 << 2) }
}

이제 MyOptionsApple 문서에 설명 된 것처럼 이 새로운 옵션 세트를 처리 할 수 있습니다. enum유사한 구문을 사용할 수 있습니다 .

let opt1 = MyOptions.FirstOption
let opt2: MyOptions = .SecondOption
let opt3 = MyOptions(4)

또한 옵션이 작동 할 것으로 예상되는 것처럼 작동합니다.

let singleOption = MyOptions.FirstOption
let multipleOptions: MyOptions = singleOption | .SecondOption
if multipleOptions & .SecondOption != nil {     // see note
    println("multipleOptions has SecondOption")
}
let allOptions = MyOptions.fromMask(7)   // aka .fromMask(0b111)
if allOptions & .ThirdOption != nil {
    println("allOptions has ThirdOption")
}

찾기 / 바꾸기없이 Swift 옵션 세트를 생성 하는 생성기를 만들었습니다 .

최신 : Swift 1.1 베타 3 수정.


답변

Xcode 6.1 베타 2는 RawOptionSetType프로토콜 을 일부 변경했습니다 (이 Airspeedvelocity 블로그 항목Apple 릴리스 정보 참조). ).

Nate Cooks 예제를 기반으로 업데이트 된 솔루션이 있습니다. 다음과 같이 자신의 옵션 세트를 정의 할 수 있습니다.

struct MyOptions : RawOptionSetType, BooleanType {
    private var value: UInt
    init(_ rawValue: UInt) { self.value = rawValue }

    // MARK: _RawOptionSetType
    init(rawValue: UInt) { self.value = rawValue }

    // MARK: NilLiteralConvertible
    init(nilLiteral: ()) { self.value = 0}

    // MARK: RawRepresentable
    var rawValue: UInt { return self.value }

    // MARK: BooleanType
    var boolValue: Bool { return self.value != 0 }

    // MARK: BitwiseOperationsType
    static var allZeros: MyOptions { return self(0) }

    // MARK: User defined bit values
    static var None: MyOptions          { return self(0) }
    static var FirstOption: MyOptions   { return self(1 << 0) }
    static var SecondOption: MyOptions  { return self(1 << 1) }
    static var ThirdOption: MyOptions   { return self(1 << 2) }
    static var All: MyOptions           { return self(0b111) }
}

그런 다음 변수를 정의하기 위해 다음과 같이 사용할 수 있습니다.

let opt1 = MyOptions.FirstOption
let opt2:MyOptions = .SecondOption
let opt3 = MyOptions(4)

비트를 테스트하려면 다음과 같이하십시오.

let singleOption = MyOptions.FirstOption
let multipleOptions: MyOptions = singleOption | .SecondOption
if multipleOptions & .SecondOption {
    println("multipleOptions has SecondOption")
}

let allOptions = MyOptions.All
if allOptions & .ThirdOption {
    println("allOptions has ThirdOption")
}


답변

설명서의 Swift 2.0 예제 :

struct PackagingOptions : OptionSetType {
    let rawValue: Int
    init(rawValue: Int) { self.rawValue = rawValue }

    static let Box = PackagingOptions(rawValue: 1)
    static let Carton = PackagingOptions(rawValue: 2)
    static let Bag = PackagingOptions(rawValue: 4)
    static let Satchel = PackagingOptions(rawValue: 8)
    static let BoxOrBag: PackagingOptions = [Box, Bag]
    static let BoxOrCartonOrBag: PackagingOptions = [Box, Carton, Bag]
}

여기에서 찾을 수 있습니다


답변

Swift 2 (현재 Xcode 7 베타의 일부로 베타)에서 NS_OPTIONS스타일 유형을 새 OptionSetType유형의 하위 유형으로 가져옵니다 . 새로운 프로토콜 확장 기능과 OptionSetType표준 라이브러리에서 구현 된 방식 덕분에 OptionsSetType가져온 동일한 함수와 메소드를 확장 하고 가져 오는 고유 한 유형을 선언 할 수 있습니다.NS_OPTIONS 스타일 유형 .

그러나 이러한 함수는 더 이상 비트 산술 연산자를 기반으로하지 않습니다. C에서 비 독점 부울 옵션 세트를 사용하려면 필드에서 마스킹 및 비트 비트가 필요합니다. 정말, 옵션 세트는 것입니다 세트 … 고유 항목의 모음. 따라서 배열 리터럴 구문에서 생성,와 같은 쿼리 ,으로 마스킹 등 OptionsSetTypeSetAlgebraType프로토콜 에서 모든 메소드를 가져 옵니다 .containsintersection


답변

//Swift 2.0
 //create
    struct Direction : OptionSetType {
        let rawValue: Int
        static let None   = Direction(rawValue: 0)
        static let Top    = Direction(rawValue: 1 << 0)
        static let Bottom = Direction(rawValue: 1 << 1)
        static let Left   = Direction(rawValue: 1 << 2)
        static let Right  = Direction(rawValue: 1 << 3)
    }
//declare
var direction: Direction = Direction.None
//using
direction.insert(Direction.Right)
//check
if direction.contains(.Right) {
    //`enter code here`
}


답변

Objective-C와 상호 운용 할 필요가없고 Swift에서 비트 마스크 의 표면 의미 를 원한다면, 일반적인 Swift 열거 형으로이를 수행 할 수있는 BitwiseOptions라는 간단한 “라이브러리”를 작성했습니다.

enum Animal: BitwiseOptionsType {
    case Chicken
    case Cow
    case Goat
    static let allOptions = [.Chicken, .Cow, .Goat]
}

var animals = Animal.Chicken | Animal.Goat
animals ^= .Goat
if animals & .Chicken == .Chicken {
    println("Chick-Fil-A!")
}

등등. 실제 비트는 여기에서 뒤집 히지 않습니다. 이들은 불투명 한 값에 대해 설정된 작업입니다. 여기서 요점을 찾을 수 있습니다 .


답변

Rickster가 이미 언급했듯이 Swift 2.0에서 OptionSetType 을 사용할 수 있습니다 . NS_OPTIONS 유형은 OptionSetType프로토콜에 따라 가져 오며 옵션에 대한 설정 인터페이스를 제공합니다.

struct CoffeeManipulators : OptionSetType {
    let rawValue: Int
    static let Milk     = CoffeeManipulators(rawValue: 1)
    static let Sugar    = CoffeeManipulators(rawValue: 2)
    static let MilkAndSugar = [Milk, Sugar]
}

이 작업 방식을 제공합니다.

struct Coffee {
    let manipulators:[CoffeeManipulators]

    // You can now simply check if an option is used with contains
    func hasMilk() -> Bool {
        return manipulators.contains(.Milk)
    }

    func hasManipulators() -> Bool {
        return manipulators.count != 0
    }
}