有名ライブラリに学ぶSwift実践テクニック

以前こちらの記事で、Alamofireを読んでいて気づいたSwiftの便利な書き方についてご紹介しました。
[Alamofireから学ぶSwift実践テクニック](http://qiita.com/yosan/items/c181766b3d1503956135)

今回は他のライブラリから、気になった書き方をご紹介したいと思います。

# 追加可能なenumのように使えるstaticプロパティ

## ライブラリ名

[SwiftyUserDefaults](https://github.com/radex/SwiftyUserDefaults)

## 内容

SwiftyUserDefaultsはUserDefaultsを便利に使うためのライブラリです。
キーの定義とsubscript引数の入れ方に特徴があります。

```swift:README.md
extension DefaultsKeys {
    static let username = DefaultsKey<String?>("username")
    static let launchCount = DefaultsKey<Int>("launchCount")
}

let username = Defaults[.username]
Defaults[.hotkeyEnabled] = true
```
`Defaults`の`subscript`の入力が「`.`」から始まっており、enumのように見えますが`DefaultsKeys`のstaticプロパティです。

staticプロパティの型が自身の型である場合、その型を引数に取る関数などで型名を省略して渡すことがでるようです。

```swift:説明用コード
class StaticPorpertyClass {
    static let p1 = StaticPorpertyClass() // 同じ型であることがポイント
}

func myFunction(_ obj: StaticPorpertyClass) {
    // ...
}

myFunction(.p1) // StaticPorpertyClass.p1としなくて良い
```

SwiftyUserDefaults.swiftの`DefaultsKeys`の定義をご参照ください。
また、NotificationCenterでも同手法が使われています。

## メリット

- 引数のパターンが`DefaultsKeys`型で制限できる。
- extensionで外部からパターンを増やすことができる。（enumで制限してしまうとライブラリ外部から`DefaultsKeys`を追加できない）
- 引数のところで「`.`」を打つだけで`DefaultsKeys`のstaticプロパティが候補で表示される。
- `DefaultsKey`に好きな情報を詰め込める。

# オリジナルextensionの入口プロパティ

## ライブラリ名
[Kingfisher](https://github.com/onevcat/Kingfisher)

## 内容
KingfisherはUIImageViewなどに画像の非同期ダウンロード機能を拡張するライブラリです。
このライブラリでは拡張対象のクラスに対し、メソッドを直接追加するのではなく、`kf`というプロパティ経由でメソッドにアクセスさせています。

```swift:README.mdより抜粋
let url = URL(string: "url_of_your_image")
imageView.kf.setImage(with: url)
```

`kf`は`Kingfisher`クラスになります。実装はこうなっています。

```swift:Kingfisher.swiftより抜粋
public final class Kingfisher<Base> {
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

/**
 A type that has Kingfisher extensions.
 */
public protocol KingfisherCompatible {
    associatedtype CompatibleType
    var kf: CompatibleType { get }
}

public extension KingfisherCompatible {
    public var kf: Kingfisher<Self> {
        get { return Kingfisher(self) }
    }
}

extension Image: KingfisherCompatible { }
#if !os(watchOS)
extension ImageView: KingfisherCompatible { }
extension Button: KingfisherCompatible { }
#endif
```

`KingfisherCompatible`をつけるだけで`kf`プロパティが追加されるようになっています。
extensionの実装は、`Base`がどのクラスかによって切り替えることができます。

```swift:ImageView+Kingfisher.swiftより抜粋
extension Kingfisher where Base: ImageView {
```

```swift:NSButton+Kingfisher.swift
extension Kingfisher where Base: NSButton {
```

この書き方はRxSwiftでも使われています。

## メリット

- `kf`がネームスペースの役割を果たすので既存メソッドと混ざらない。
- 既存メソッドと重複した名前も使用可能。

ライブラリを作るときなどに、拡張対象の型が多い場合、あるいは拡張されるプロパティやメソッドが多い場合に便利そうです。

# 可変長引数subscript

## ライブラリ名

[SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)

## 内容

SwiftyJSONはJSONのパーサーですが、要素にアクセスしやすいよういろいろ工夫がされています。その中で、可変長引数を持つ`subscript`が定義されています。

```swift:SwiftyJSON.swiftより抜粋
public subscript(path: JSONSubscriptType...) -> JSON {
    get {
        return self[path]
    }
    set {
        self[path] = newValue
    }
}
```

JSONの深い所にある要素にアクセスするために使われています。

```swift:README.mdより抜粋
json["list",3,"what"] = "that"
```

うまく使えば、便利な型が作れそうです。
例として複数の値を取り出すDictionary風の型を作ってみました。

```swift:説明用コード
struct MultiKeyDictionary<Key: Hashable, Value> {
    
    private let _dictionary: [Key : Value]
    
    init(_ dictionary: [Key : Value]) {
        _dictionary = dictionary
    }
    
    subscript(keys: Key...) -> [Value] {
        return keys.flatMap { return _dictionary[$0] }
    }
}

let source = [
    "a" : "hoge",
    "b" : "fuga",
    "c" : "foo",
    "d" : "bar"
]
let mkDic = MultiKeyDictionary(source)

print(mkDic["a"]) // -> ["hoge"]
print(mkDic["a", "d"]) // -> ["hoge", "bar"]
```

`subscript`を使った場合は、可変長も検討してみると面白そうです。

## メリット

- 可変長引数の`subscript`を1引数の延長として実装できれば、直感的でより便利な型になる。

# custom operatorのチェーン

## ライブラリ名

[SwiftState](https://github.com/ReactKit/SwiftState)

## 内容

SwiftStateはcustom operatorがいろいろ定義されていて、状態遷移を定義したり実行したりするのが特徴です。一つの状態遷移を表すのは`.state0 => .state1`と書けるのですが、連続した複雑な状態遷移も`.state0 => .state1 => .state2`のように書けるよう工夫しています。

```swift:説明用コード
machine = StateMachine<MyState, NoEvent>(state: .state0) { machine in
        machine.addRouteChain(.state0 => .state1 => .state2, handler: { _ in
        print("0 -> 1 -> 2")
    })
}
```

custom operatorの戻り値の型も、再度同じcustom operatorの引数として受け付けるようにするのがポイントです。実際のコードではいろんなパターンが網羅されています。TransitionChain.swiftをご参照ください。細かい工夫ですが気持ちよく書けるので、custom operatorを実装する場合は考慮すると良さそうです。


## メリット

- より便利で直感的にcustom operatorを使うことができる。

# 最後に

いくつか自分が気になった例を書いてみました。
特にSwiftyUserDefaultsとKingfisherのパターンは使い所が多そうですので、自分のプロジェクトにもすぐ応用できそうです。
SwiftyJSONとSwiftStateの例は、ライブラリを自作する際に参考にできそうです。