स्विफ्ट में NS_OPTIONS-स्टाइल बिटकॉइन एन्यूमरेशन कैसे बनाएं?


137

सी एपीआई के साथ बातचीत करने के बारे में एप्पल के दस्तावेज में, वे बताते हैं कि जिस तरह से NS_ENUMसी-स्टाइल एन्यूमरेशन स्विफ्ट एन्यूमरेशंस के रूप में आयात किए जाते हैं। यह समझ में आता है, और चूंकि स्विफ्ट में गणना आसानी से प्रदान की जाती है, क्योंकि enumमूल्य यह देखना आसान है कि हमारा खुद का निर्माण कैसे किया जाए।

इसके अलावा, यह NS_OPTIONSसी-स्टाइल विकल्पों के बारे में यह कहता है :

स्विफ्ट NS_OPTIONSमैक्रो के साथ चिह्नित विकल्पों को भी आयात करता है । जबकि विकल्प आयातित गणनाओं के समान व्यवहार करते हैं, विकल्प कुछ बिटवाइज़ ऑपरेशंस जैसे , और &, का भी समर्थन कर सकते हैं । ऑब्जेक्टिव-सी में, आप निरंतर शून्य ( ) के साथ सेट एक खाली विकल्प का प्रतिनिधित्व करते हैं । स्विफ्ट में, किसी भी विकल्प की अनुपस्थिति का प्रतिनिधित्व करने के लिए उपयोग करें।|~0nil

यह देखते हुए कि optionsस्विफ्ट में कोई वैल्यू टाइप नहीं है , हम किस तरह से काम करने के लिए सी-स्टाइल विकल्प वेरिएबल बना सकते हैं?


3
@ मैट के बहुत प्रसिद्ध "NSHipster" में इसका व्यापक वर्णन है RawOptionsSetType: nshipster.com/rawoptionsettype
Klaas

जवाबों:


258

स्विफ्ट 3.0

लगभग स्विफ्ट 2.0 के समान। OptionSetType को OptionSet नाम दिया गया था और सम्मेलन द्वारा enums को निचला मामला लिखा जाता है।

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विकल्प प्रदान करने के बजाय , स्विफ्ट 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

स्विफ्ट 2.0 में, प्रोटोकॉल एक्सटेंशन इन के लिए अधिकांश बॉयलरप्लेट का ख्याल रखते हैं, जो अब एक ऐसी संरचना के रूप में आयात किया जाता है जो इसके अनुरूप होता है OptionSetType। ( RawOptionSetTypeस्विफ्ट 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

ऑब्जेक्टिव-सी विकल्पों (स्विफ्ट द्वारा आयात किया गया को देखते हुए 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) }
}

अब हम इस नए विकल्प सेट का इलाज कर सकते हैं MyOptions, जैसे कि Apple के प्रलेखन में वर्णित है: आप 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")
}

मैंने सभी खोज / प्रतिस्थापन के बिना एक स्विफ्ट विकल्प सेट बनाने के लिए एक जनरेटर का निर्माण किया है

नवीनतम: स्विफ्ट 1.1 बीटा 3 के लिए संशोधन।


1
मेरे लिए यह तब तक काम नहीं आया जब तक कि मैंने valueUInt32। आपको किसी भी कार्य को परिभाषित करने की आवश्यकता नहीं है, प्रासंगिक कार्य पहले से ही RawOptionSets (जैसे func |<T : RawOptionSet>(a: T, b: T) -> T) के लिए परिभाषित हैं
डेविड लॉसन

धन्यवाद, कार्यों के बारे में महान बिंदु - मुझे लगता है कि संकलक उन लोगों के बारे में शिकायत कर रहा था, जब मेरे पास बाकी प्रोटोकॉल अनुरूपता नहीं थी। आपने किन समस्याओं के साथ देखा UInt? यह मेरे लिए ठीक काम कर रहा है।
नैट कुक

2
क्या कोई समाधान है जो संरचना के बजाय एनम का उपयोग करता है? मुझे मेरा उद्देश्य- c ...
jowie

1
@ जौईenum CollisionTypes: UInt32 { case Player = 1 case Wall = 2 case Star = 4 case Vortex = 8 case Finish = 16 }
mccoyLBI

1
इस उदाहरण में, Apple के डॉक्स वास्तव में अच्छे हैं।
श्री रोजर्स

12

Xcode 6.1 Beta 2 ने RawOptionSetTypeप्रोटोकॉल में कुछ बदलाव लाए (देखें एयरस्पिडेवेलोस ब्लॉग प्रविष्टि और Apple रिलीज़ नोट )।

नैट कुक के उदाहरण के आधार पर यहां एक अद्यतन समाधान है। आप अपने स्वयं के विकल्प को इस तरह निर्धारित कर सकते हैं:

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

8

दस्तावेज़ से स्विफ्ट 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]
}

आप इसे यहाँ पा सकते हैं


6

स्विफ्ट 2 में (वर्तमान में Xcode 7 बीटा के भाग के रूप में बीटा), NS_OPTIONS-स्टाइल प्रकार नए OptionSetTypeप्रकार के उपप्रकार के रूप में आयात किए जाते हैं । और नए प्रोटोकॉल एक्सटेंशन सुविधा के लिए धन्यवाद और OptionSetTypeमानक पुस्तकालय में जिस तरह से लागू किया जाता है, आप अपने स्वयं के प्रकारों की घोषणा कर सकते हैं जो OptionsSetTypeसभी समान कार्यों और विधियों को NS_OPTIONSप्राप्त करते हैं जो आयातित प्रकार के होते हैं।

लेकिन वे कार्य अब बिटवाइट अंकगणितीय ऑपरेटरों पर आधारित नहीं हैं। सी में गैर-विशेष बूलियन विकल्पों के एक सेट के साथ काम करने के लिए एक क्षेत्र में मास्किंग और ट्विडलिंग बिट्स की आवश्यकता होती है जो एक कार्यान्वयन विवरण है। वास्तव में, विकल्पों का एक सेट एक सेट है ... अद्वितीय वस्तुओं का एक संग्रह। तो प्रोटोकॉल OptionsSetTypeसे सभी विधियां मिलती हैं SetAlgebraType, जैसे सरणी शाब्दिक वाक्य रचना से निर्माण, जैसे सवाल contains, साथ मास्किंग intersection, आदि (कोई और अधिक याद रखने के लिए कि किस अजीब चरित्र का उपयोग करने के लिए सदस्यता परीक्षण!)


5
//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`
}

4

यदि आपको ऑब्जेक्टिव-सी के साथ हस्तक्षेप करने की आवश्यकता नहीं है और बस स्विफ्ट में बिट मास्क की सतह शब्दार्थ चाहते हैं , तो मैंने एक सरल "लाइब्रेरी" लिखा है जिसे बिटवाइज़ओक्शन्स कहा जाता है जो नियमित स्विफ्ट एनुमरेशन्स के साथ ऐसा कर सकते हैं, जैसे:

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

और इसी तरह। कोई वास्तविक बिट्स यहाँ फ़्लिप किया जा रहा है। ये अपारदर्शी मूल्यों पर संचालन सेट हैं। आप यहाँ गिस पा सकते हैं ।


@ChrisPrince सबसे अधिक संभावना है कि यह स्विफ्ट 1.0 के लिए बनाया गया था और तब से अपडेट नहीं किया गया है।
ग्रेगरी हिगले

मैं वास्तव में इस के एक स्विफ्ट 2.0 संस्करण पर काम कर रहा हूं।
ग्रेगरी हिगले

2

जैसा कि रिकस्टर ने पहले ही उल्लेख किया है, आप स्विफ्ट 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
    }
}

2

यदि केवल कार्यक्षमता की आवश्यकता है, तो विकल्पों के साथ संयोजन करने |और जांचने का एक तरीका है यदि संयुक्त विकल्पों में &नैट कुक के उत्तर के विकल्प के साथ एक विशेष विकल्प होता है :

एक विकल्प 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) 

2

बस किसी और के लिए एक अतिरिक्त उदाहरण पोस्ट करना जो सोच रहा था कि क्या आप यौगिक विकल्प जोड़ सकते हैं। आप कर सकते हैं, और वे जोड़ते हैं जैसे आप उम्मीद करते हैं कि यदि आप अच्छे पुराने बिटफील्ड के लिए उपयोग किए जाते हैं:

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

1

किसी और ने इसका उल्लेख नहीं किया है - और मैंने कुछ छेड़छाड़ के बाद उस पर इस तरह का आरोप लगाया है - लेकिन एक स्विफ्ट सेट काफी अच्छी तरह से काम करता है।

अगर हम सोचते हैं (शायद एक वेन आरेख के लिए?) के बारे में क्या एक बिट मुखौटा वास्तव में प्रतिनिधित्व कर रहा है, यह संभवतः एक खाली सेट है।

बेशक, पहले सिद्धांतों से समस्या का सामना करने में, हम बिटवाइज़ ऑपरेटरों की सुविधा खो देते हैं, लेकिन शक्तिशाली सेट-आधारित तरीके प्राप्त करते हैं जो पठनीयता में सुधार करते हैं।

यहाँ उदाहरण के लिए मेरी छेड़छाड़ है:

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

मुझे यह अच्छा लगता है क्योंकि मुझे लगता है कि यह समस्या के पहले सिद्धांतों के दृष्टिकोण से आता है - स्विफ्ट की तरह - सी-स्टाइल समाधानों को अपनाने की कोशिश करने के बजाय।

कुछ ओब्ज-सी उपयोग मामलों को भी सुनना चाहेंगे जो इस अलग प्रतिमान को चुनौती देंगे, जहां पूर्णांक कच्चे मान अभी भी योग्यता दिखाते हैं।


1

आदेश मुश्किल सा पदों कोडिंग से बचने के लिए है, जो अपरिहार्य है का उपयोग करते समय में (1 << 0), (1 << 1), (1 << 15)आदि या भी बदतर 1, 2, 16384आदि या कुछ हेक्साडेसिमल भिन्नता, एक पहले एक में बिट्स को परिभाषित करता है हो सकता है 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)
}

बस जोड़ा गया उदाहरण जहां आपको कुछ भी कोड करने की आवश्यकता नहीं है।
पीटर अहलबर्ग

1

मैं निम्नलिखित का उपयोग करता हूं मुझे उन दोनों मूल्यों की आवश्यकता है जिन्हें मैं प्राप्त कर सकता हूं, कच्चे माल को अनुक्रमित सरणियों और झंडे के लिए मूल्य।

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

1

पुन: कई विकल्पों के साथ विकल्प सेट का उपयोग करते हुए सैंडबॉक्स और बुकमार्क क्रिएशन

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

सभी विकल्पों के परस्पर अनन्य नहीं होने पर उपयोगी रचनाओं के लिए विकल्पों को संयोजित करने की आवश्यकता है।


0

नैट का जवाब अच्छा है लेकिन मैं इसे 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)
}

0

स्विफ्ट 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]
}

1
यह कमोबेश इस उत्तर में पहले से ही शामिल है ।
पेंग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.