UIFeedbackGeneratorをiOS10未満対応アプリで楽に書けるUtility

# UIFeedbackGenerator

iOS10にて[UIFeedbackGenerator](https://developer.apple.com/reference/uikit/uifeedbackgenerator)というAPIが追加されています。

"iOS10 + iPhone7のTapticEngine" をアプリ内から操作できるAPIです。
iPhone7だと UISwitchやUIScrollViewなどの操作時に「ﾊﾟｺｯ!」というフィードバックがありますよね。あれっす。

## iOS10の時だけ実行されるUIFeedbackGeneratorのラッパークラスを作りました

これを自分のプロジェクトにも導入しようと思いましたがiOS10未満もサポートしているため都度 `#available`が必要になってしまいます。
もう少し気軽にフィードバックを追加していきたいなと思ったので、
ややdynamicな感じですがiOS10の時だけ実行されるUIFeedbackGeneratorのラッパーAPIを用意してみました。

### 使い方はこんな感じ

```swift
// Notification
NotificationFeedbacker().feedback(style: .success)

// Impact
ImpactFeedbacker(style: .heavy).feedback()

// Selection
SelectionFeedbacker()
```

### ソースコード

以下ソースコードです。

```swift
import UIKit

public final class ImpactFeedbacker {

  public enum Style {
    case light
    case medium
    case heavy
  }

  @available(iOS 10.0, *)
  private var feedbackGenerator: UIImpactFeedbackGenerator? {
    get {
      return feedbackGeneratorSource as? UIImpactFeedbackGenerator
    }
    set {
      feedbackGeneratorSource = newValue
    }
  }

  private var feedbackGeneratorSource: Any?

  public init(style: Style) {
    if #available(iOS 10.0, *) {
      switch style {
      case .light:
        feedbackGenerator = UIImpactFeedbackGenerator(style: .light)
      case .medium:
        feedbackGenerator = UIImpactFeedbackGenerator(style: .medium)
      case .heavy:
        feedbackGenerator = UIImpactFeedbackGenerator(style: .heavy)
      }
      feedbackGenerator?.prepare()
    } else {
      feedbackGeneratorSource = nil
    }
  }

  public func feedback() {
    if #available(iOS 10.0, *) {
      feedbackGenerator?.impactOccurred()
      feedbackGenerator?.prepare()
    } else {
    }
  }
}

public final class SelectionFeedbacker {

  @available(iOS 10.0, *)
  private var feedbackGenerator: UISelectionFeedbackGenerator? {
    get {
      return feedbackGeneratorSource as? UISelectionFeedbackGenerator
    }
    set {
      feedbackGeneratorSource = newValue
    }
  }

  private var feedbackGeneratorSource: Any?

  public init() {
    if #available(iOS 10.0, *) {
      feedbackGenerator = UISelectionFeedbackGenerator()
      feedbackGenerator?.prepare()
    } else {
      feedbackGeneratorSource = nil
    }
  }

  public func feedback() {
    if #available(iOS 10.0, *) {
      feedbackGenerator?.selectionChanged()
      feedbackGenerator?.prepare()
    } else {
    }
  }
}

public final class NotificationFeedbacker {

  public enum Style {
    case success
    case warning
    case error
  }

  @available(iOS 10.0, *)
  private var feedbackGenerator: UINotificationFeedbackGenerator? {
    get {
      return feedbackGeneratorSource as? UINotificationFeedbackGenerator
    }
    set {
      feedbackGeneratorSource = newValue
    }
  }

  private var feedbackGeneratorSource: Any?

  public init() {
    if #available(iOS 10.0, *) {
      feedbackGenerator = UINotificationFeedbackGenerator()
      feedbackGenerator?.prepare()
    } else {
      feedbackGeneratorSource = nil
    }
  }

  public func feedback(style: Style) {
    if #available(iOS 10.0, *) {
      switch style {
      case .success:
        feedbackGenerator?.notificationOccurred(.success)
      case .warning:
        feedbackGenerator?.notificationOccurred(.warning)
      case .error:
        feedbackGenerator?.notificationOccurred(.error)
      }
      feedbackGenerator?.prepare()
    } else {
    }
  }
}
```

https://gist.github.com/muukii/09d1829e1f7d686a47310b9dabf75104

## 補足

「ﾊﾟｺｯ!」 が気持ちよすぎて全てのボタンに追加したくなってしまいますが、そういうわけにはいかないんですね。

Appleのガイドラインには適切な使い方が記述されていました。

https://developer.apple.com/ios/human-interface-guidelines/interaction/feedback/#haptics


## まとめ

**ﾊﾟｺｯ!**