Swift 2でOptionalがどれだけ便利になったか、Swift1.2とdiffをとってみた

Swift 2の進化といえばいいのか、Objective Cも含めたiOS SDK全体の進化でもあるのか微妙だったりしますが。

# Swift 2 !! #

OSS化で盛り上がってますが、Swift Blog の次の記述も気になってます。

> Swift-er SDKs: Swift 2 works even better with the Apple SDKs, thanks in part to two new features in Objective-C: nullability annotations and generics. The SDKs have been updated to annotate API that cannot return nil so you don’t need to use optionals as often. And with a true generics system employed by the SDKs you can more often preserve detailed type information in your Swift 2 code.

> (勝手な翻訳)
> Swift-er SDK(よりSwift向けなSDK、って意味？): Swift2は、nullabilityアノテーションとジェネリクスというObjective-Cの２つの新機能のおかげで、Apple SDKとよりうまく動かせます。nilを返すことがないAPIにアノテーションが付与されることで、不必要にOptionalを使わなくて済むようにSDKはアップデートされました。
> さらに、ジェネリクスの機構が導入されたことで、より詳細な型情報をSwift2のコードに引き渡すことができます。

Swift2.0以前は、せっかくSwiftがOptional型を持つことでnil問題に堅牢につくれるはずが、
iOS SDKがOptionalのないObjC時代のままなために、iOS SDKのAPIとの境界ではOptionalが有効活用されてなくて残念な感じでした。

それが、これは、もしかして、nullabilityアノテーションとかを駆使してSDKが刷新され、「引数にnilを渡していいか」「nilが返却されることがあるか」が完璧にコンパイルレベルで検知可能になったということですか！？

さらに、Objective-Cのコレクション型(NSArrayやNSDictionary)は保持する型に制約がなく強制的に Array<AnyObject>状態だったのが、キチンとなんの型のコレクションかわかるようになったと！？

と期待が高まったので、試しにSwift2 @ Xcode7betaで書かれたソースを Swift1.2 @ Xcode6.3と比較してどう変わったのかみてみました。

結論としては、

- Optionalをより有効活用できるSDKになっていそうなところが確認できた

- ジェネリクスのお陰でコレクションの型情報がより正確に、っていうのは、今回の例ではそのものずばりな変化は無し

# diff Swift 1.2 (Xcode6.3) vs Swift 2 (Xcode7 beta)

Master-Detail Application をそれぞれで新規作成したdiff
(CoreDataは無しでジェネレート)

## AppDelegate.swift

### navigationController.topViewController

Swift 1.2

```swift
navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
```

Swift 2

```swift
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
```

UINavigationController.topViewController が ImplicitUnwrap(!)からOptional(?)に。
! だとnilチェックをしなくても何も言われないのに対して、Optinalだとnilチェックが強制される。
nullabilityのチェックが強化されている感。

ただしここでは ! でunwrapしてしまっているので台無しではある笑

### splitViewController(splitViewController, collapseSecondaryViewController, ontoPrimaryViewController)

Swift 1.2

```swift
     func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController!, ontoPrimaryViewController primaryViewController:UIViewController!) -> Bool {
```

Swift 2

```swift
     func splitViewController(splitViewController: UISplitViewController, collapseSecondaryViewController secondaryViewController:UIViewController, ontoPrimaryViewController primaryViewController:UIViewController) -> Bool {
```

collapseSecondaryViewController, ontoPrimaryViewControllerが !(nilかもしれないけどnilチェックを強制しない)から無印(nilはありえない)に。
引数にnilが渡ってくることがありえないのに nilチェックをしないといけないのかもしれない、という状況だったのが
明確にnilはあり得ないと表現されるように。
まさにブログの記述のとおり。


###  guard

Swift 1.2

```swift
         if let secondaryAsNavController = secondaryViewController as? UINavigationController {
             if let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController {
                 if topAsDetailController.detailItem == nil {
                     // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
                     return true
                 }
             }
```

Swift 2

```
         guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
         guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
         if topAsDetailController.detailItem == nil {
             // Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
             return true
```

新しいguard syntaxが使われることで記述が簡潔に。

## MasterViewController.swift

Swift 1.2

```swift
     override func awakeFromNib() {
         super.awakeFromNib()
         if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
             self.clearsSelectionOnViewWillAppear = false
             self.preferredContentSize = CGSize(width: 320.0, height: 600.0)
         }
     }
```

Swift 2


```
     override func viewWillAppear(animated: Bool) {
         self.clearsSelectionOnViewWillAppear = self.splitViewController!.collapsed
         super.viewWillAppear(animated)
     }
```

この差分はなんだろう。。。

タブレットデバイスだったときに実行されていた処理が、常に実行されるように？
prefferedContentSizeを指定しなくなったのは、わざわざ指定する必要がないよう初期値がより最適になったのか、
単に実装が変わって挙動も変わっているだけなのか

### as 連鎖

Swift 1.2

```
             self.detailViewController = controllers[controllers.count-1].topViewController as? DetailViewController
```

Swift 2

```
             self.detailViewController = (controllers[controllers.count-1] as! UINavigationController).topViewController as? DetailViewController
```

これはSwift 1.2 のときから使えてる記法で、単にジェネレートされるソースがちょっと変わっただけの模様。
Swift2の方のコードをSwift1.2で書いてもちゃんと動く。

### tableView.indexPathForSelectedRow

Swift 1.2


```swift
             if let indexPath = self.tableView.indexPathForSelectedRow() {
```

Swift 2

```
             if let indexPath = self.tableView.indexPathForSelectedRow {
```

Optionalの使い方的にはなんの変化もないのに、
なぜかメソッドがプロパティに変化・・・

### tableView.dequeueReusableCellWithIdentifier

Swift 1.2

```swift
         let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
```

Swift 2

```swift
         let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
```


dequeueReusableCellWithIdentifierの返り値がAnyObjectからUITableViewCellに！
見た目的にはジェネリクス関係無いけど、内部的にコレクション持っている、とかで実はジェネリクスの恩恵なのかも

## DetailViewController.swift

- AnyObject

Swift 1.2

```swift
         if let detail: AnyObject = self.detailItem {

```

Swift 2

```swift
         if let detail = self.detailItem {
```

Swift 1.2 で Swift 2の書き方をすると

> Constant `detail` inferred to have type `AnyObject`, which may be unexpected

と警告されてたのが、警告されなくなった。

単に警告が無くなったのか、それとも、ここでは self.detailItemが本当にAnyObject型で宣言されてるので、その辺を判断した上で警告を出さなくしてるのか

# 以上！

最近Optionalがすごい便利な気がしてきていて、でもSDKとの境界部分が結局ほぼノーOptionalなのがもったいないなーと思っていたところだったので、
Swift2のこのアップデートは個人的にはどストライク。

Swift2でnilチェック漏れを一掃できそうな予感。

[ブログ: Swift 2でOptionalがどれだけ便利になったか、Swift1.2とdiffをとってみた](http://blog.bookside.net/2015/06/09/swift2%E3%81%A7optional%E3%81%8C%E3%81%A9%E3%82%8C%E3%81%A0%E3%81%91%E4%BE%BF%E5%88%A9%E3%81%AB%E3%81%AA%E3%81%A3%E3%81%9F%E3%81%8Bdiff%E3%82%92%E3%81%A8%E3%81%A3%E3%81%A6%E3%81%BF%E3%81%9F/)