SwiftでOptionSet

# OptionSetType

Swift2.0で新しくOptionSetTypeプロトコルが導入され、
簡単にOptionSetを定義できるようになりました。

# Sample

今回はUInt8型とし、最大8個のオプションを定義できるようにします。

```swift:CountryOption.swift
struct CountryOption: OptionSetType {
    
    let rawValue: UInt8
    init(rawValue: UInt8) { self.rawValue = rawValue }
    
    // それぞれの桁にオプションを定義
    static let Japan         = CountryOption(rawValue: 0b00000001)
    static let UnitedStates  = CountryOption(rawValue: 0b00000010)
    static let UnitedKingdom = CountryOption(rawValue: 0b00000100)
    static let China         = CountryOption(rawValue: 0b00001000)
    static let France        = CountryOption(rawValue: 0b00010000)
    static let Australia     = CountryOption(rawValue: 0b00100000)
    static let India         = CountryOption(rawValue: 0b01000000)
    static let Canada        = CountryOption(rawValue: 0b10000000)
    static let All           = CountryOption(rawValue: 0b11111111)
    
    // 値のグループをオプションとして定義することもできる。
    static let Asia        : CountryOption = [.Japan, .China, .India]
    static let Europe      : CountryOption = [.UnitedKingdom, .France]
    static let NorthAmerica: CountryOption = [.UnitedStates, .Canada]
}
```

# contains
値が含まれるかどうかを判定する。

```swift
let europe: CountryOption = .Europe
europe.contains(.France) // true
europe.contains(.India)  // false
```

# insert, remove

```swift
var wishToGo: CountryOption = [.India, .UnitedStates, .UnitedKingdom, .France]
```

**insert**
新しくオプションを追加する。

```swift
wishToGo.insert(.China)
// wishToGo = [.India, .UnitedStates, .UnitedKingdom, .France, .China]
```

**remove**
オプションを取り除き、取り除いたものを返す。
指定したものを含んでいなかった場合はnilを返す。
※説明が難しいのでコードを見てください。

```swift
let removed1 = wishToGo.remove(.UnitedStates)      // removed1 = .UnitedStates
let removed2 = wishToGo.remove([.Canada, .France]) // removed2 = nil
// wishToGo = [.India, .UnitedKingdom, .China]
```

# exclusiveOr, exclusiveOrInPlace → XOR演算
exclusiveOrは共通部分を除いたものを返す。
exclusiveOrInPlaceは演算結果で書き換える。

![Exclusive.png](https://qiita-image-store.s3.amazonaws.com/0/84014/46c95ba2-f68d-8faa-1b6e-36134731cb82.png)

```swift
var pacific : CountryOption = [.UnitedStates, .China, .Japan, .Australia, .Canada]
let atlantic: CountryOption = [.UnitedStates, .UnitedKingdom, .France, .Canada]

let either = pacific.exclusiveOr(atlantic)
// either = [.China, .Japan, .Australia, .UnitedKingdom, .France]
```

# intersect, intersectInPlace → AND演算
intersectは共通部分を返す。
intersectInPlaceは演算結果で書き換える。

![Intersect.png](https://qiita-image-store.s3.amazonaws.com/0/84014/254c5098-e839-5dee-9fe4-b526d7f29189.png)

```swift
var pacific : CountryOption = [.UnitedStates, .China, .Japan, .Australia, .Canada]
let atlantic: CountryOption = [.UnitedStates, .UnitedKingdom, .France, .Canada]

let both = pacific.intersect(atlantic)
// both = [.UnitedStates, .Canada]
```

# union, unionInPlace → OR演算
unionは要素を合わせたものを返す。
unionInPlaceは演算結果で書き換える。

![Union.png](https://qiita-image-store.s3.amazonaws.com/0/84014/c546aa87-ed44-0fdb-cf24-0124ce4fedfb.png)

```swift
var visited: CountryOption = [.Japan, .China, .UnitedStates]
visited.unionInPlace([.France, .Australia])
// visited = [.Japan, .China, .UnitedStates, .France, .Australia]
```

結果の通り、**insertとunionInPlaceは同じ**です。

# 出力
そのままだと出力が不便。

```swift
print(CountryOption.Asia) // "CountryOption(rawValue: 73)"
```

文字列で出力するよう拡張。

```swift
extension CountryOption: CustomStringConvertible {
    var description: String {
        let strings = ["日本", "アメリカ", "イギリス", "中国", "フランス", "オーストラリア", "インド", "カナダ"]
        var members = [String]()
        for (flag, string) in strings.enumerate() where self.contains(CountryOption(rawValue: 1 << (UInt8(flag)))) {
            members.append(string)
        }
        return members.description
    }
}
```

```swift
print(CountryOption.Asia) // "["日本", "中国", "インド"]"
```

# 参考

Swift Standard Library Reference
https://developer.apple.com/library/prerelease/mac/documentation/Swift/Reference/Swift_OptionSetType_Protocol/index.html#//apple_ref/swift/intfm/OptionSetType/s:FeRq_Ss13OptionSetTypezq_qq_S_7Element_SsS_6removeuRq_S_zq_qq_S_7Element_FRq_Fqq_S_7ElementGSqqq_S_7Element_

Swift 2.0 の新しいOption、OptionSetType
http://www.toyship.org/archives/2208


Notes from WWDC 2015: The Enumerated Delights of Swift 2.0 Option Sets
http://www.informit.com/articles/article.aspx?p=2420231

# おわりに
便利になったOptionSetを使って今度はUIViewに枠線をつけたいと思います！