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の列挙型がもつ、
「列挙型自体を値型としてオブジェクトとして扱え、プロパティーやメソッドも定義できる」
という性質は本当に便利だ。
これを使って、コードをすっきりさせよう。