XCode7にあげた際のSwift1.2とSwift2の違いメモ


## はじめに

XCode7で変わった点をまとめます。
といっても、公式なものではなく僕がXcode7にバージョンをあげた時に気づいた事を書いてます。

※Swift2の新しい構文などについては取り上げてません。

## `Convert`が`var`→`let`までしてくれる
僕はこの辺はほとんどやってたつもりでしたが、`Convert`に指摘されました。
なので以下のような構文は`Convert`が変更してくれます。

```swift
func test() {
	var hoge = Hoge()
	hoge.test()
}
```

上記のように特に`hoge`インスタンスを変更してない場合は

```swift
func test() {
	let hoge = Hoge()	// ←変えてくれる
	hoge.test()
}
```

このように変更してくれます。

## コンパイルが早くなった。
コンパイル速度よりも、それに伴ってコード補完が早くなりました。
僕は`古いMacBook Air`で開発しているので、これは嬉しい。
ただ、使い続けるとどうなるかはまだ分かりません。

## 警告が増えた。
今までは使ってない変数があっても警告は出ませんでしたが今回からは警告が出ます。
僕は主に以下のような構文を使ってたのでこれらが警告になりました。

```swift
if let foo = hoge as? Foo
	// fooは条件を満たすかどうかのためでしか使ってない。
end
```

これは以下のように変更しないと警告になります。

```swift
if let _ = hoge as? Foo
	// fooは条件を満たすかどうかのためでしか使ってない。
end
```

また無駄な`weak`に関しても警告がでます。

```swift
CallBlock() { [weak self] in
	// selfを使ってない。
},
```

コピペコードでありがちな上記なようなコードにも警告を出してくれます。
助かります。

### 注意点。
僕はgfxさんの[Swiftでマルチスレッド時の同期処理はどうやるのか](http://qiita.com/gfx/items/532f9f975de5a965c58a)を使用して同期処理をしてましたがこれは警告が発生してます。

```swift
class AutoSync {
    let object : AnyObject

    init(_ obj : AnyObject) {
        object = obj
        objc_sync_enter(object)
    }

    deinit {
        objc_sync_exit(object)
    }
}
```

これを以下のように使っていた。

```
let lock = AutoSync(self)
```

警告を解除するために

```
let _ = AutoSync(self)
```

とやると、その時点でメモリが解放されてしまいスレッドブロックをしてもらえなくなります。
（`_`は`weak`と同様の扱いのようで`retain count`を増やしてくれません。）

なので、適当なメソッドを入れて対応しました。

```swift
class AutoSync {
    let object : AnyObject

    init(_ obj : AnyObject) {
        object = obj
        objc_sync_enter(object)
    }
    
    func end() {}

    deinit {
        objc_sync_exit(object)
    }
}
```

```swift
let lock = AutoSync(self)

...何かの処理

lock.end()
```

警告がでても無視する方はそのまま使ってもいいかと思います。

## countやenumerate、containsが自然な形になった。
もともと`count`や`enumerate`は`Swift`クラスが提供してくれてたので

```swift
count([])
count("test")

contains(["test", "abc"], "test")	// "test"が配列にあるか？
for (key, value) in enumerate({"key": value}) {
}
```

という構文で対応してたのですが、以下のように自然な形になりました。
特に`contains`はどっちがどっちだっけと迷うこともあったので助かります。

```swift
[].count
"test".characters.count

["test", "abc"].contains("test")	// "test"が配列にあるか？
for (key, value) in {"key": value}.enumerate() {
}
```

ところで`Swift`クラスは無くなったのでしょうか・・・？
あれはオブジェクト指向から逸脱してる特殊クラスだったので廃止されたのかな・・・？

## NSMutableDictionary as? [String: AnyObject]ができなくなった。
僕は`Objective-c`から受け取ったデータを無理やり`[String: AnyObject]`に変換してました。

```switf
let objData:NSMutableDictionary = obj.hash()
let dic = objData as! [String: AnyObject]
```

しかし、これはもう使えなくなってました。
コンパイルエラーが発生するため素直に`NSMutableDictionary`のまま処理をすることにしました・・・。
ただ、[Objective-cのNSMutableArrayとNSMutableDictionaryをSwiftで使う際にはまったこと](http://qiita.com/syou007/items/8bed05ab894af9198e39)の`NSMutableArray`→`NSMutableDictionary`のパターンはうまくできました・・・。
この辺りは謎です。

## printlnがなくなりました。
これからは`print`構文のみになります。

## convenience initに`?`が
コンビニエンスイニシャライズが少し変わりました。

```swift
required convenience init(coder aDecoder: NSCoder) {
	// 復元処理
}
```

これが以下のようになります。


```swift
required convenience init?(coder aDecoder: NSCoder) {
	// 復元処理
}
```

## test(_ value:int? = nil)が警告に
Swift1.2までは以下のように呼びしたい場合に`_`が必要でした。

```swift
let hoge = Hoge()
hoge.test()	// 初期値を与えなくない。
hoge.test(1)	// 初期値を与えたい。
```

これを行うためには以下の定義をする必要がありました。

```swift
func test(_ value:Int? = nil) {
	// _が必要だった。
}
```

この`_`がない場合は`hoge.test(value: 1)`と記載しなければならなかったのですが`_`はなくてもOKになりました。

## 親クラスで定義しているプロトコルを子で定義する必要がなくなりました。
今までは親クラスが定義しているクラスも子で定義する必要がありました。

```swift
class Parent: NSObject, NSCoding {
}
class Child: Parent, NSCoding {
}
```

これがコンパイルエラーになり、以下のように子ではいちいち定義しなくても良くなりました。

```swift
class Parent: NSObject, NSCoding {
}
class Child: Parent {
}
```

## 逆に省略できなくなりました。
今まではメソッドで使わない変数を以下のように省略できました。

```swift
func test([Hoge], foo: Foo) {}
```

これは以下のようになります。

```swift
func test(_: [Hoge], foo: Foo) {}
```

当たり前といえば当たり前ですが、僕は`override`する時に度々使ってたので今後気をつけます。

## Objective-cのメソッドの返却値がOptionalになった気がする。
まだ全部確認が取れてませんが、今までよりも`Objective-c`の呼び出しが硬くなった気がします。

```swift
obj-c.parent.addChild(self)
```

みたいな構文が以下のようになります。

```swift
obj-c.parent!.addChild(self)
```

## 第一引数を推測してくれるようになった。
もともとSwiftでは以下の構文でした。

```swift
func test(arg1:Int, arg2:Int) {}
test(1, arg2: 2)
```

このように第一引数の名前は省略できます。
しかし、第一引数が省略可能だった場合は名前の省略ができませんでした。

```swift
func test(arg1:Int = 0, arg2:Int = 0) {}
test(arg1: 1, arg2: 2)		// arg1が省略できない。
```

Swift2からは上記の場合でも第一引数の省略ができます。（というかしないとコンパイルエラーになります。）

```swift
func test(arg1:Int = 0, arg2:Int = 0) {}
test(1, arg2: 2)		// arg1は不要
```

## 複雑な構文がNGになりました。
複雑な構文をブロック内に記載するとコンパイルエラーになるようになりました。

```swift
CallBack = {
	$0.items.filter{ $0.type == .A || $0.type == .B }.count
}
```

このような構文を書くと以下のエラーが発生します。

```
Expression was too complex to be solved in reasonable time; consider breaking up the expression into distinct sub-expressions
```

これは以下のように記載します。

```swift
CallBack = {
	let items = $0.items.filter{ $0.type == .A || $0.type == .B }
	return items.count
}
```

ブロック内で２行以上に渡る場合は`return`が必須なのでお忘れなく。

## Enumのswitch#defaultに警告が出ます。
今までは以下の構文でも警告が出ませんでした。

```swift
enum HogeType {
	case A
	case B
}

switch {
case A:
	// 何かの処理
case B:
	// 何かの処理
default:
	// 何かの処理
}
```

僕は後々増える予定のEnumを`default`で拾う予定のコードを書いてたのですが、これは警告が出ます。
普通に使う場合はとても良い変更です。

## String#toInt()が廃止に
今までは文字列をInt型に変換する時に以下のように行ってました。

```swift
let intValue = "1".toInt()!
```

これは廃止され

```swift
let intValue = Int("1")!
```

になりました。
Int()がOptional型で返却されるというのに注目です。
（これが自然かどうか微妙ですが。`convenience init`に`?`がつくようになったため可能になったのでしょう。きっと。※実装を見てもそんなコードは見当たりませんでしたが・・・どうやってるのかな？）

## CFBundleIdentifierが$(PRODUCT_BUNDLE_IDENTIFIER)に
info.plistの`CFBundleIdentifier`に`$(PRODUCT_BUNDLE_IDENTIFIER)`が適用されます。
僕に対したメリットがないですが、、、

ただ、この変更のためかXCode7対応時に`CFBundleIdentifier`が消えてしまうという謎の障害に頭を悩ましました。
もし以下のエラーが出た場合は上部にある`BundleIdentifier`が正しいか見てみましょう。

![スクリーンショット](https://qiita-image-store.s3.amazonaws.com/0/79216/7d7fab07-8624-397b-b8cc-43544c5ea175.png "スクリーンショット")

愚かにも僕はこれで相当手こずりました・・・。

## iOS7のシミュレーターがなくなりました。
僕のような個人アプリを作ってる人は良いですが、企業でやってる人は注意してください。
XCode7からはiOS7のシミュレーターがなくなってるので実機でしかテストができないです。

ただ、実機テストが無料になったので端末さえあればそんなに問題にはならないと思います。

## Pod Installが必要の場合も
僕の場合は`cocoaPod`の古いバージョンを使ってたため`Pod`周りでエラーが出ました。

```sh
$ bundle exec gem install cocoapods
```

で`pod`を最新にして

```sh
$ pod install
```

をすれば解決します。

## まとめ
警告が増えたのはとても良かったです。
僕は結構硬いコードを書いてたつもりだったのですが、いくつか引っかかってしまったので助かりました。

また、コンパイル速度が上がったのも良い変更です。
XCode7にあげるのはなかなか苦痛を伴いますが、これからSwift2を楽しめるのであげて良かったかなと思います。

あとコンバータが結構優秀で助かりました。
なにも見ずに`save`しても多分問題は発生しません。(Swift1.2の時はそれなりにエラーが発生してた・・・）

## おまけ
僕は`cocos2d`で作ったプログラムだったので、XCode7にあげた時に結構きっつい対応が必要でした。
とにかくエラーの原因がわからず最後の最後まで以下のエラーに悩まされました。

```
object file (/libcocos2d.a(OALSimpleAudio.o)) was built for newer iOS version (9.0) than being linked (7.0)
```

この手のワーニングはもう諦めました・・・

あと、プログラムは動くけれどエラーが出るという現象も発生しました。
[こちら](http://forum.cocos2d-objc.org/t/xcode-7-ios9-beta/17346/13)に解決策が書かれてましたが、`metallib`を作らないわけなので抜本的な解決策ではありません。。。
僕は`metal`を使ってないので問題ないのですが、`metal`を使ってる人は注意が必要です。

### gitを使ってからやる方が良いです。
忘れてました。
XCode7にあげる前に必ず`git`へコミットしておきましょう！

いざという時に戻せる安心感と、プロジェクトファイルとかが勝手に書き換えられた場合の差分を見たりできます。
僕は`git`にも随分助けられました。

では、Swift2を楽しんできます。