俺の考えた最強のNSIndexPathのenum管理法

作ってみたらわりといい感じだったので共有

#やりたいこと
1.セクション名、セル名を**enumで完全に管理**する
2.**switchやifをネストさせず**、また**数値を使わずにenumで分岐**したい
3.UITableViewで使うので**セクション数**と**セクションごとのセル数**を取得したい
4.不正なindexPathはguardしたい

#前提
Swift2.3

![CscKDMOUsAA3dtn.jpg](https://qiita-image-store.s3.amazonaws.com/0/24979/c03c38c5-0c39-ce46-ee86-2c9b97a1102f.jpeg)

このようなUITableViewをenumで管理してみます。

##やってみた

まずはenumのカウントを出来るようにしたり、管理用のプロトコルを定義する。
なくてもいいけど、セクションやローを増やしたり減らしたりする時に弄る箇所が少なくなるし、見通しもいいので定義しておきましょう。

```swift
//カウント可能なenum拡張
protocol Countable { }
extension Countable where Self : RawRepresentable, Self.RawValue == Int  {
  static func count() -> Int {
    var count = 0
    while let _ = Self(rawValue: count) { count += 1 }
    return count
  }
}

//ローとセクション用にプロトコルを分ける
protocol IndexRow: Countable { }
protocol IndexSection: Countable { }
```


次にメインのenumの実装です。
Sectionに管理するセクション一覧を、Rowには一覧とセクションごとの処理を追加します。
Rowにまとめるのは見通しを良くするためなので、不要であれば外に出しても良いです。
また、セクション名とRow.Hogehogeの名前も一緒である必要はありません。

```swift
import UIKit

//セクションの管理enum
enum Section: Int, IndexSection {
  case Instruments
  case UiAnimation
  case Network
  case Iad
  
  //セクションごとのロー数を返す
  func rowCount() -> Int {
    switch self {
    case .Instruments: return Row.Instruments.count()
    case .UiAnimation: return Row.UiAnimation.count()
    case .Network:   return Row.Network.count()
    case .Iad:   return Row.Iad.count()
    }
  }
}

//ローの管理enum
enum Row {
  enum Instruments: Int, IndexRow {
    case Logging
  }
  
  enum UiAnimation: Int, IndexRow {
    case Animation
  }
  
  enum Network: Int, IndexRow {
    case Status
  }
  
  enum Iad: Int, IndexRow {
    case FillRate
    case AdRefreshRate
    case Hightlight
    case Unlimited
  }
  
  //セクションに対応するロー要素を返す
  static func create(section: Section, rowIndex: Int) -> IndexRow? {
    switch section {
    case .Instruments: return Instruments(rawValue: rowIndex)
    case .UiAnimation: return UiAnimation(rawValue: rowIndex)
    case .Network:     return Network(rawValue:     rowIndex)
    case .Iad:         return Iad(rawValue:         rowIndex)
    }
  }
}
```

最後にNSIndexPathにprivate extensionを生やします

```
private extension NSIndexPath {
  func parse() -> (Section, IndexRow)? {
    guard let section = Section(rawValue: section) else { return nil }
    guard let row     = Row.create(section, rowIndex: row) else { return nil }
    return (section, row)
  }
}
```


##使ってみる
実際使ってみます。

```swift

//サンプル用のIndexPath
let indexPath = NSIndexPath(forRow: 0, inSection: 0)

//IndexPathから生成、不正の場合はnilが返る
guard let (section, row) = indexPath.parse() else { return }

//セクション名・セル名で分岐
switch (section, row) {
case (Section.Instruments, Row.Instruments.Logging):
  break
case (Section.UiAnimation, Row.UiAnimation.Animation):
  break
case (Section.Network, Row.Network.Status):
  break
case (Section.Iad, Row.Iad.FillRate):
  break
case (Section.Iad, Row.Iad.AdRefreshRate):
  break
case (Section.Iad, Row.Iad.Hightlight):
  break
case (Section.Iad, Row.Iad.Unlimited):
  break
default: break
}

//セクション数
let sectionCount = Section.count()

//セクションのセル数
let rowCount     = section.rowCount()

```

**さいこうでは…**

indexPathの要素だけから生成されたsectionとrowがswitchでキレイに分岐されていきます。
セル数やセクション数も簡単に取れるのでUITableViewでも利用出来そうです。
設定画面などで活躍しそう。
何か改善点あればコメントください！