Passion+Action+Sincerely=Success!

週末にのみ趣味でコーディングするおやじの備忘録

Swiftのenumが素敵すぎる

Swiftの列挙型(enum)が便利すぎて泣けてきた。
今回は、Swiftの列挙型がもつ、固有な性質を使って、コードのリファクタリングを実施してみた。


Swiftの列挙型には、以下の固有な性質があるんです!素敵だ。
1. メンバーに具体的な値をいれる必要はない。メンバーを値として扱える。
2. メンバーに付随する型を設定できる。
3. メンバーに値を入れた場合は、Objective-CのNS_ENUMと同様に扱える。
4. 列挙型自体を値型としてオブジェクトとして扱え、プロパティーやメソッドも定義できる。


特に、今回は#3と#4の性質を使って、コードをリファクタリングしてみる。

問題: 以下の関数を実際に使用する際、category値として、segmentedContrrol.selectedSegmentIndexを入力する。そのため、Int型で宣言してあるが、現在のコード上、実際には0-3の値しかとらない。例えば、4以上の値が入ってくることはない。でも、この関数のシグネチャだけでは、categoryとしてどんな値を取りうるのか分からず、将来、バグを発生させてしまう可能性がある。このような時にもちろん列挙型が使えるわけだ。

func urlWithSearchText(searchText: String, category: Int) -> NSURL {
        var entityName: String
        switch category {
            case 1: entityName = "musicTrack"
            case 2: entityName = "software"
            case 3: entityName = "ebook"
            default: entityName = ""
        }

        let escapedSearchText =
            searchText.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
        let urlString = String(format:
            "http://itunes.apple.com/jp/search?term=%@&limit=200&entity=%@", escapedSearchText, entityName)
        let url = NSURL(string: urlString)
        return url!
}

上記をリファクタリングしたのが以下だ。ここで、#3の性質を使って、メンバーに値を設定している。これにより、urlWithSearchTextの引数は、Int型ではなく、Category型となり、値としては、0-3までしか扱えなくなった。

enum Category: Int { 
  case All = 0
  case Music = 1 
  case Software = 2 
  case EBook = 3
}

private func urlWithSearchText(searchText: String, category: Category) -> NSURL {
  var entityName: String
  switch category { 
    case .All: entityName = ""
    case .Music: entityName = "musicTrack"
    case .Software: entityName = "software"
    case .EBook: entityName = "ebook"
  }
  
  let escapedSearchText = . . .
  
・・・・・・・・・・・

上記では、urlWithSearchText関数内で、Category値に従って、さらにentityName値を決定しており、なんかすっきりしない。そこでで、さらに、#4の性質を使って、すっきりさせるぜ!

Swiftの列挙型は本当に素敵だ。なんと、Computed propertyを定義できるんだ。つまり、Categoryに、entityNameというcomputed propertyを追加できちゃうんだな。
追加したCateogyが以下だ。

enum Category: Int { 
  case All = 0
  case Music = 1 
  case Software = 2 
  case EBook = 3

  var entityName: String {
    switch self {
      case .All: return "" 
      case .Music: return "musicTrack"
      case .Software: return "software" 
      case .EBook: return "ebook"
    } 
  }
}

これにより、urlWithSearchText関数は、以下のようにすっきりできる。

private func urlWithSearchText(searchText: String,category: Category) -> NSURL {
   let entityName = category.entityName  // cateogory値に基づいて決定されるentityName値を取り出せる。

   let escapedSearchText = . . .

Swiftの列挙型がもつ、
 「列挙型自体を値型としてオブジェクトとして扱え、プロパティーやメソッドも定義できる」
という性質は本当に便利だ。

これを使って、コードをすっきりさせよう。