Swift Code改善tips

swiftらしいコード書けるように最近ずっとリファクタリングしてて、正しいかどうか自分もわからないけど、一応自分いいと思ったtipをまとめたいと思います。

# Stringよりenumを使う
例: stroyboard からview controllerを取得

``` Swift

let searchChannelListViewController = UIStoryboard(name: "Search", bundle: nil).instantiateViewControllerWithIdentifier("SearchChannelList")

guard let searchChannelListViewController = searchChannelListViewController else{
       return 
}

```

Stringのデメリット:

 * nilではありえないとわかったとしても毎回nil判定もしくは！しないといけない.
 * typoしやすいし、実行時しか違ったことに気づかない
 
enumのメリット:

* typoするとコンパイル エラー
* enumに定義されたやつは必ず値があると定義できる

上のコードちょっとリファクタリング:

``` swift 
 private enum StoryboardName:String {
        case ChannelDetail = "ChannelDetail"
        case Search = "Search"
    }
    private enum ViewControllerIdentifier:String {
        case playlist = "playlist"
        case SearchChannelList = "SearchChannelList"
    }

    private func viewController(storyboardName storyboardName:StoryboardName,viewControllerId:ViewControllerIdentifier?) -> UIViewController {

        if let viewControllerId = viewControllerId {
            return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateViewControllerWithIdentifier(viewControllerId.rawValue)
        }
        // enum使えば値があるのはここで保証する
        return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateInitialViewController()!
    }
    
    // これで取ったview controller 全部nilではなくなる
    let channelDetailViewController = viewController(storyboardName:.ChannelDetail, viewControllerId:nil)
    let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList)
```

# default valueを使う
前のコードstoryboardのroot view controllerとるのにviewControllerId:nil渡すのは直感ではない、できるかぎりstoryboardNameだけで渡したい。この時はパラメーターdefault value.

```swift
private func viewController(storyboardName storyboardName:StoryboardName,viewControllerId:ViewControllerIdentifier? = nil) -> UIViewController {
 ....
}

// viewControllerId:nil を削除
let channelDetailViewController = viewController(storyboardName:.ChannelDetail)
let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList)

```


# as! より genericsを使う

上のコードはUIViewController返すだけなので、そのViewControllerに対して特定な操作したいときにtype変換する必要が出ってきます。つまり

```swift

let channelDetailViewController = viewController(storyboardName:.ChannelDetail) as! ChannelDetailViewController
let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList) as! searchChannelListViewController

```

as! ちょっと汚いね。。こういう場合はgenerics！

``` swift 
private func viewController<T:UIViewController>(storyboardName storyboardName:StoryboardName,viewControllerId:ViewControllerIdentifier? = nil,type:T.Type) -> T {
        if let viewControllerId = viewControllerId {
           return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateViewControllerWithIdentifier(viewControllerId.rawValue) as! T
        }
        return UIStoryboard(name: storyboardName.rawValue, bundle: nil).instantiateInitialViewController() as! T
    }

//これでdown castする必要がなくなる、なとなく前より綺麗になりました
let channelDetailViewController = viewController(storyboardName:.ChannelDetail,type: ChannelDetailViewController.self)
let searchChannelListViewController = viewController(storyboardName:.Search,viewControllerId:.SearchChannelList,type: searchChannelListViewController.self) 

```


# いらないものは _ で隠す
例: UI animation 

``` swift 
UIView.animateWithDuration(0.25, animations: {
  //make same super cool animation
}, completion: {
  finished in
  // same clean up
})
```
completion blockのほう finishedが返ってきてるけど、実際には使われてなくて、
_ を使って隠す

``` swift 
UIView.animateWithDuration(0.25, animations: {
  //make same super cool animation
}, completion: {
  _ in
  // same clean up
})
```

# struct namespace

struct/enum内でstructを定義できるので、namespaceとして使える.

例: 色定義

``` swift 
struct ColorPalette {
      static let Red = UIColor(red: 1.0, green: 0.1491, blue: 0.0, alpha: 1.0)
      static let Green = UIColor(red: 0.0, green: 0.5628, blue: 0.3188, alpha: 1.0)
      static let Blue = UIColor(red: 0.0, green: 0.3285, blue: 0.5749, alpha: 1.0)
  
      struct Gray {
          static let Light = UIColor(white: 0.8374, alpha: 1.0)
          static let Medium = UIColor(white: 0.4756, alpha: 1.0)
          static let Dark = UIColor(white: 0.2605, alpha: 1.0)
     }
 }

 let red = ColorPalette.Red
 let darkGray = ColorPalette.Gray.Dark
```

# didSetを使ってIBOutletするviewカスタマイズする

普通のviewDidLoadでcustomする

``` swift 

class ViewController: UIViewController {
    @IBOutlet weak var myLabel: UILabel!
    @IBOutlet weak var myButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // viewカスタマイズ
        configureViews()
    }

    func configureViews() {
        myLabel.textColor = UIColor.purpleColor()
        myButton.tintColor = UIColor.redColor()
    }
}

```

didSet内でcustomする

```swift

class ViewController: UIViewController {
    @IBOutlet weak var myLabel: UILabel! {
        didSet {
            myLabel.textColor = UIColor.purpleColor()
        }
    }

    @IBOutlet weak var myButton: UIButton! {
        didSet {
            myButton.tintColor = UIColor.redColor()
        }
    }
}
```