既存プロジェクトを swift2.0,Xcode7 へ移行した時のTips


移行した時のメモを残していきます。細かい構文などについては触れません。
swift1.2 > 2.0
Xcode6.4 > ~~7.0~~ 7.1

iPhone6: iOS ~~9.0.1~~ 9.1
下記で書いている実行時のことは、実機で確認したものになります。

※ 当記事のミスや追記した方が良いことがあれば、コメントを頂けると嬉しいです。


# Xcodeの複数バージョンを共存させる

> 前提として、すでにXcodeをインストールしているとします。

[Apple公式ダウンロードページ - Downloads for Apple Developers](https://developer.apple.com/downloads/) から
Xcode7.0などインストールしたいバージョンのdmgファイルをダウンロードする。

ある程度時間がかかるので、その間にすでにインストールされているXcodeと共存させるために
すでにインストールされている Xcode.app を Xcode6.4.app などバージョンが分かる名前に変更する。

後はダウンロード完了を待って、dmgを開き中に入っているXcode.appをいつも通りドラッグアンドドロップするだけです。
こちらのXcode.appも名前を変更してバージョンを明記しておくといいと思います。

### ※ 追記

Carthageを利用している場合、このままでは`carthage update`で以下の様なエラーが発生する可能性があります。

```
A shell task failed with exit code 72:
xcrun: error: unable to find utility "xcodebuild", not a developer tool or in PATH
```

この場合は以下のように、Xcodeのパスを変更してあげれば治ります。

```
sudo xcode-select -switch /Applications/Xcode7.0.app/Contents/Developer
```


# 既存プロジェクトを swift2.0,Xcode7.x に対応させる

## 既存プロジェクトを初めて開いた時

swidt2.0に対応させるようにコードを変更するか問われるダイアログが表示されます。
これによって、ある程度は自動でコードを変更してくれます。
Before・Afterのプレビューが表示されるので、この時にどんな風にコードが変わるのか見ておくと良いでしょう。

![スクリーンショット 2015-09-24 7.58.17.png](https://qiita-image-store.s3.amazonaws.com/0/42327/03f5737f-9106-a58d-7bcb-b315ad09d0f4.png "スクリーンショット 2015-09-24 7.58.17.png")


## You must rebuild it with bitcode enabled

GoogleAnalyticsを利用していて発生しました。

```
ld: '/hoge-project/Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a(GAITrackerImpl.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture armv7
```

利用しているライブラリやフレームワークがbitcodeに対応していない場合に発生します。
Xcode7.0のデフォルトでbitcodが有効になっているので

**Build Setting > Build Options > Enable Bitcode で YES になっているものを NO へ変更することで無効にできます。**

### ※ 追記

bitcodeをNOにしてストアへ出す際、Archive > Validate で `include bitcode.` のチェックを外す必要があります。

しない場合、このようなエラーが発生しvalidateが完了しません。

```
The archive did not contain <DVTFilePath:~~~
```

bitcodeについては、すでにQiitaに書いてくださっている人がいるので参考ページを載せておきます。

参考ページ
> [LLVM bitcode基礎知識](http://qiita.com/gamako/items/f37dbb05de9d3832ce6b)
> [Error during submission](http://stackoverflow.com/questions/32925498/error-during-submission)


## URLScheme が開けない

Instagramへ遷移しようと canOpenURL を実行して発生しました。

```
-canOpenURL: failed for URL: "instagram://app" - error: "This app is not allowed to query for scheme instagram"
```

外部アプリを開く際には、使用する URLScheme を列挙する必要があります。

**Info.plist に LSApplicationQueriesSchemes: Array を追加し、その中に String で利用したいSchemeを書くことで開けるようになります。**

![スクリーンショット 2015-09-24 9.02.40.png](https://qiita-image-store.s3.amazonaws.com/0/42327/f0088fe9-a2d5-3c68-543f-a2f776780508.png "スクリーンショット 2015-09-24 9.02.40.png")


参考ページ
> [iOS 9 not opening Instagram app with URL SCHEME](http://stackoverflow.com/questions/30987986/ios-9-not-opening-instagram-app-with-url-scheme)
> [【追記】iOS9でcanOpenURLを有効にする方法](http://nlogic.jp/?p=417)
> [iOS9でのcanOpenURL](http://psychlab.jugem.jp/?eid=712)


## WebView でページが開けない

WebView で広告を表示しようとして発生しました。

```
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
```

デフォルトではhttpでの接続ができなくなっています。(App Transport Security)
http接続をしたい場合、AppTransportSecurity を全部or一部(ドメイン)無効にします。

**Info.plist に App Transport Security Settings: Dictionary** で追加し、その中に

* 全部無効にする場合: **Allow Arbitrary Loads: Boolean YES** として追加する。

![スクリーンショット 2015-11-04 10.01.45.png](https://qiita-image-store.s3.amazonaws.com/0/42327/52f5d641-9d17-7076-a69d-549900dd2180.png "スクリーンショット 2015-11-04 10.01.45.png")


* 一部無効にする場合 **(推奨)** : **Exception Domains: Dictionary** で 追加し、その中に ドメイン > **NSTemporaryExceptionAllowsInsecureHTTPLoads: Boolean YES**, **NSTemporaryExceptionRequiresForwardSecrecy: Boolean NO** として追加する。

 サブドメインも許可する場合 **NSIncludesSubdomains: Boolean YES** として追加する。


![スクリーンショット 2015-11-04 10.00.00.png](https://qiita-image-store.s3.amazonaws.com/0/42327/da2710ce-3b26-ee56-5d60-9f86db910a31.png "スクリーンショット 2015-11-04 10.00.00.png")




### ※ 追記

URLに接続できなかった場合、以下のようなログが流れます。

```
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
```

このままでは実際にどのようなURLが引っかかったか分からないので、ログを見る必要があります。
通信にCFNetworkというフレームワークが利用されているので、そのログを出力するために下記のコードをAppDelegate.swiftに記述します。

```
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        setenv("CFNETWORK_DIAGNOSTICS","3",1)
        
        return true
]
```

実装後に実行して、実際に通信で`NSURLSession/NSURLConnection HTTP load failed`を発生させます。
Window > Devices を開き、実行した時のデバイスでアプリを選択して歯車マークを押し、Download Container を選択しログを任意の場所に保存します。

保存したログ `com.example.app 2015-10-11 01:28.36.311.xcappdata` はディレクトリになっています。
`com.example.app 2015-10-11 01:28.36.311.xcappdata/AppData/Library/Logs/CrashReporter/CFNetwork_com.example.app_0000.nwlrb.log` のようなファイルにログが出力されているので、適当なもので開きます。

`NSURLSession/NSURLConnection HTTP load failed`エラーの末尾にある -9802 などの数字を検索して、どのようなURLが引っかかっているのかを確認することができます。


参考ページ
> [iOS9 ATS問題](http://qiita.com/yanayanalte/items/e6d83c12af77fa238a58)
> [[iOS 9] iOS 9 で追加された App Transport Security の概要](http://dev.classmethod.jp/smartphone/iphone/ios-9-intro-ats/)
> [【iOS9】HTTP→HTTPSだと！App Transport Security(ATS)について](http://mushikago.com/i/?p=6150)
> [iOS9 : App Transport Securityの確認方法](http://techlog.voyagegroup.com/entry/2015/09/04/182843)



## CGContextSaveGState, CGContextTranslateCTM, CGContextRestoreGState invalid context 0x0

### ※この問題はXcode7.1で修正され、発生しなくなりました

ステータスバーを隠そうとして発生しました。

```
CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
CGContextTranslateCTM: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
CGContextRestoreGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
```

Info.plist > View controller-based status bar appearance を NO にすると発生するようです。
Xcode7.0 になってから発生する不具合のようで Xcode7.1 beta2 でも実行してみたが変わりませんでした。
現在これの対処はできないようです。

参考ページ
> ['invalid context 0x0' after Migration to iOS 9](http://stackoverflow.com/questions/32540095/invalid-context-0x0-after-migration-to-ios-9)


### ※ 追記

確定の情報ではなく可能性として考えられることですが
iOS9から、UIAplicationクラスのステータスバーに関する[メソッドが一部、Deprecated](https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/doc/uid/TP40006728-CH3-SW170)になっています。
これが原因かもしれません。しかし、他に代わりになるメソッドは見当たりません。
試しに実機iOS8で実行してみたところ、このエラーは発生しませんでした。

現状の対応としてはViewController側で動的に隠すことぐらいでしょうか。

```
override func prefersStatusBarHidden() -> Bool {
    return true
}
```

ただ、UIImagePickerControllerなどを表示する際はステータスバーが表示されてしまいます。
その後に最後、ステータスバーも隠すことが可能です。
しかし、これも戻った時一瞬ステータスバーが見えてしまうので良くない動作です。
なので完全な動作を求める場合、やはり公式の対応待ちという状態だと思います。

参考ページ
> [Error Message in Debug Area](https://forums.developer.apple.com/thread/13683)