39
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-09-15

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

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

#前提
Swift2.3

CscKDMOUsAA3dtn.jpg

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

##やってみた

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

//カウント可能な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の名前も一緒である必要はありません。

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

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


//サンプル用の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でも利用出来そうです。
設定画面などで活躍しそう。
何か改善点あればコメントください!

39
37
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
37

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?