programing

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

showcode 2023. 4. 20. 23:23
반응형

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

C에 관한 에서는 C API의 에 대해 설명하고 .NS_ENUM【C】【Swift】【Import】 Swift의 는 것은은 the the the the the the the the the enum로 되기 때문에 쉽게 이해할 수 있다. 스위프트enum가치 유형 자체 제작 방법을 쉽게 확인할 수 있습니다.

아래에는 '우리'에 대해서 이렇게 적혀 요.NS_OPTIONS- C - "C" :

는 Swift로 .NS_OPTIONS 옵션은 와 동일하게 은 ""와 일부 도 있습니다. 옵션이 가져온 열거와 유사하게 동작하는 반면 옵션은 다음과 같은 일부 비트 연산을 지원할 수도 있습니다.&,| , , , , 입니다.~Objective-C)으로 빈 옵션세트를 .0에서는 를 합니다. 스위프트nil옵션이 없음을 나타냅니다.

그런 게 없다는 걸 고려하면options재빠르다 C-Style C-Style C-Style C-Style C-Style C-Style C-Style?

Swift 3.0

Swift 2.0과 거의 동일합니다.OptionSetType의 이름이 OptionSet으로 변경되었으며 규칙에서 enum은 소문자로 작성되었습니다.

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)
}

「 」를 하는 대신에, 「 」를 합니다.noneSwift 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")
}

Swift 2.0

2. 보일러 플레이트는 Swift 2.0에 .이러한 보일러 플레이트는 현재 다음을 준수하는 구조로 Import되고 있습니다.OptionSetType ( . )RawOptionSetTypeSwift 2 ) 2 ) 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)
}

를 set-based semantics와 함께 사용할 수 되었습니다.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

(Swift Import 옵 Objective-C ) 。UIViewAutoresizing는 옵션이 '어느 정도'로을 알 수structRawOptionSetType은 곧 '다행하다'와 _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) }
}

이옵션 세트인 '어울리지 않을 수 없다'를 수 있습니다.MyOptions되어 있는 의 메뉴얼을 사용할 수 .enum- 구문 - like 구문:

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의 변경 사항.

6.1 Xcode 6.1이 되었습니다.RawOptionSetTypeprotocol(이 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]
}

여기서 찾을 수 있습니다.

2), Swift 2(「Xcode 7」)에서는, Swift 2(「Xcode 7」)가 사용되고 있습니다.NS_OPTIONS-style 유형은 새 유형의 하위 유형으로 가져옵니다.새로운 Protocol Extensions 기능과 방법 덕분에OptionSetType는 표준되어 있기 때문에 자신의 할 수 .을 사용법OptionsSetType.NS_OPTIONS- get - style type get.

그러나 이러한 함수는 더 이상 비트 연산자를 기반으로 하지 않습니다.C에서 비배타적 부울 옵션 세트를 사용하는 경우 필드의 마스킹 및 트위들링 비트를 사용해야 한다는 것은 구현 세부 사항입니다.정말 옵션 세트란...독특한 아이템의 컬렉션그렇게OptionsSetType프로토콜에서 모든 메서드를 가져옵니다. 예를 들어 어레이 리터럴 구문에서 생성, 쿼리 등입니다.contains과 함께 , " " "intersection (를 어느

//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에서 비트 마스크의 표면 의미만 원하는 경우 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 유형은 에 준거하여 Import됩니다.OptionSetType "" "set-like" "set-like" "set-like" "set-like" 를 제공합니다.

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
    }
}

하는 |에 특정 되어 있는지 합니다.&네이트 쿡의 답변에 대한 대안은 다음과 같습니다.

" " 를 만듭니다.protocol로 되어 있습니다.| ★★★★★★★★★★★★★★★★★」&:

protocol OptionsProtocol {

    var value: UInt { get }
    init (_ value: UInt)

}

func | <T: OptionsProtocol>(left: T, right: T) -> T {
    return T(left.value | right.value)
}

func & <T: OptionsProtocol>(left: T, right: T) -> Bool {
    if right.value == 0 {
        return left.value == 0
    }
    else {
        return left.value & right.value == right.value
    }
}

이제 다음과 같은 옵션 구조를 쉽게 만들 수 있습니다.

struct MyOptions: OptionsProtocol {

    private(set) var value: UInt
    init (_ val: UInt) {value = val}

    static var None: MyOptions { return self(0) }
    static var One: MyOptions { return self(1 << 0) }
    static var Two: MyOptions { return self(1 << 1) }
    static var Three: MyOptions { return self(1 << 2) }
}

다음과 같이 사용할 수 있습니다.

func myMethod(#options: MyOptions) {
    if options & .One {
        // Do something
    }
}

myMethod(options: .One | .Three) 

복합 옵션을 조합할 수 있는지 궁금하신 분들을 위해 추가 예시를 올렸습니다.사용할 수 있습니다.또한 오래된 비트필드에 익숙해지면 예상대로 조합할 수 있습니다.

struct State: OptionSetType {
    let rawValue: Int
    static let A      = State(rawValue: 1 << 0)
    static let B      = State(rawValue: 1 << 1)
    static let X      = State(rawValue: 1 << 2)

    static let AB:State  = [.A, .B]
    static let ABX:State = [.AB, .X]    // Combine compound state with .X
}

let state: State = .ABX
state.contains(.A)        // true
state.contains(.AB)       // true

를 평평하게 한다.[.AB, .X][.A, .B, .X]( 미미의의 ( ( ( ) : )

print(state)      // 0b111 as expected: "State(rawValue: 7)"
print(State.AB)   // 0b11 as expected: "State(rawValue: 3)"

그 외에는 아무도 언급하지 않았습니다.그리고 제가 조금 손질한 후에 우연히 알게 되었습니다만, 스위프트 세트는 꽤 잘 작동하는 것 같습니다.

비트 마스크가 실제로 무엇을 나타내는지(Venn 다이어그램에 따라) 생각해 보면 빈 세트일 수 있습니다.

물론 첫 번째 원칙에서 문제에 접근하면 비트 연산자의 편의성을 잃지만 가독성을 향상시키는 강력한 집합 기반 방법을 얻게 된다.

예를 들면 다음과 같습니다.

enum Toppings : String {
    // Just strings 'cause there's no other way to get the raw name that I know of...
    // Could be 1 << x too...
    case Tomato = "tomato"
    case Salami = "salami"
    case Cheese = "cheese"
    case Chicken = "chicken"
    case Beef = "beef"
    case Anchovies = "anchovies"

    static let AllOptions: Set<Toppings> = [.Tomato, .Salami, .Cheese, .Chicken, .Anchovies, .Beef]
}

func checkPizza(toppings: Set<Toppings>) {
    if toppings.contains(.Cheese) {
        print("Possible dairy allergies?")
    }

    let meats: Set<Toppings> = [.Beef, .Chicken, .Salami]
    if toppings.isDisjointWith(meats) {
        print("Vego-safe!")
    }
    if toppings.intersect(meats).count > 1 {
        print("Limit one meat, or 50¢ extra charge!")
    }

    if toppings == [Toppings.Cheese] {
        print("A bit boring?")
    }
}

checkPizza([.Tomato, .Cheese, .Chicken, .Beef])

checkPizza([.Cheese])

저는 이것이 문제에 대한 첫 번째 원칙적인 접근에서 나온다고 생각하기 때문에 좋다고 생각합니다. 스위프트와 마찬가지로요. C 스타일의 해결책을 적용하려고 하는 것이 아닙니다.

또한 정수 원시 값이 여전히 장점을 보여주는 이 다른 패러다임에 도전하는 몇 가지 Obj-C 사용 사례도 듣고 싶습니다.

하기 비트의 위치를 하드코딩 할 .(1 << 0),(1 << 1),(1 << 15) 또는 보다 더 것은1,2,16384또는 몇 16진수 변동은 '16' 또는 '16'의할 수 .enum다음으로 enum이 비트 서수 계산을 하도록 하겠습니다.

// Bits
enum Options : UInt {
    case firstOption
    case secondOption
    case thirdOption
}

// Byte
struct MyOptions : OptionSet {
    let rawValue: UInt

    static let firstOption  = MyOptions(rawValue: 1 << Options.firstOption.rawValue)
    static let secondOption = MyOptions(rawValue: 1 << Options.secondOption.rawValue)
    static let thirdOption  = MyOptions(rawValue: 1 << Options.thirdOption.rawValue)
}

rawValue(인덱스 어레이용)와 flags용(플래그용)의 두 가지 값이 모두 필요합니다.

enum MyEnum: Int {
    case one
    case two
    case four
    case eight

    var value: UInt8 {
        return UInt8(1 << self.rawValue)
    }
}

let flags: UInt8 = MyEnum.one.value ^ MyEnum.eight.value

(flags & MyEnum.eight.value) > 0 // true
(flags & MyEnum.four.value) > 0  // false
(flags & MyEnum.two.value) > 0   // false
(flags & MyEnum.one.value) > 0   // true

MyEnum.eight.rawValue // 3
MyEnum.four.rawValue  // 2

더 필요한 경우 계산된 속성을 추가하십시오.

enum MyEnum: Int {
    case one
    case two
    case four
    case eight

    var value: UInt8 {
        return UInt8(1 << self.rawValue)
    }

    var string: String {
        switch self {
        case .one:
            return "one"
        case .two:
            return "two"
        case .four:
            return "four"
        case .eight:
            return "eight"
        }
    }
}

re: 여러 옵션 세트를 사용하여 샌드박스 및 북마크 작성

let options:NSURL.BookmarkCreationOptions = [.withSecurityScope,.securityScopeAllowOnlyReadAccess]
let temp = try link.bookmarkData(options: options, includingResourceValuesForKeys: nil, relativeTo: nil)

모든 옵션이 상호 배타적이지 않을 때 유용한 크리에이션을 위한 옵션 조합이 필요한 솔루션.

네이트의 답변은 좋지만, 저는 이렇게 DIY로 하겠습니다.

struct MyOptions : OptionSetType {
    let rawValue: Int

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

타입을 하다, 3 use에서는 「Swift 3」(Swift 3 )OptionSet

struct ShippingOptions: OptionSet {
    let rawValue: Int

    static let nextDay    = ShippingOptions(rawValue: 1 << 0)
    static let secondDay  = ShippingOptions(rawValue: 1 << 1)
    static let priority   = ShippingOptions(rawValue: 1 << 2)
    static let standard   = ShippingOptions(rawValue: 1 << 3)

    static let express: ShippingOptions = [.nextDay, .secondDay]
    static let all: ShippingOptions = [.express, .priority, .standard]
}

언급URL : https://stackoverflow.com/questions/24066170/how-to-create-ns-options-style-bitmask-enumerations-in-swift

반응형