TodayExtension を objective-c から Swift 3.0 へ移行するときにやったこと

全てのソースを Swift へ移行したいと思いつつも時間はかかるし、まずは核となる機能よりも周辺から段階的に進めたいと、みなさん考えると思います。私もそうでした。

そこで、まずは TodayExtension を objective-c から Swift 3.0 へ移行することにしました。そして、つい最近移行が完了しました。ネット上の TodayExtension の情報は古いものが多く、いろいろ調べたので、誰かの参考になればと思い、Qiitaに投稿する。

# 移行前
- TodayExtensionは objective-c のみ使用している
- 本体アプリは objective-c と Swift 3.0 の両方を使ってる
- 本体アプリは `-Prefix.pch` を作成して共通で使い回すクラスのヘッダーファイルをまとめてある
- objective-c から Swift を利用するとき、いちいち `-Swift.h` を import するのが面倒なので `-Prefix.pch` に書いている

# 移行後
- TodayExtensionは全て Swift 3.0 になった :tada: 
- TodayExtensionは本体アプリの `-Prefix.pch`、`-Swift.h`、`-Bridging-Header.h` を参照している :tada: 
- 本体アプリは objective-c と Swift 3.0 の両方を使用中

# 移行完了までにやったこと
## 1. TodayExtension の `-Prefix.pch` を作成
- TodayExtensionでも `-Prefix.pch` を作成する。そして、本体アプリで使用しており、かつ TodayExtension でも使用したい objective-c のヘッダーファイルを書いておく
- 次に TodayExtension でも使用したい objective-c のクラスを、本体だけでなく TodayExtension でもビルドの対象にする。
- このとき Target Membership に**チェックを入れるのは実装ファイル（.m）のみでOK**

実装ファイル（.m） の Target Membership にチェック | 
--- | 
<img src="https://qiita-image-store.s3.amazonaws.com/0/37385/e47b5e1e-a8ba-5bd8-7ccb-0b9fe26b0545.png" width="320"/> | 


## 2. TodayExtension の `-Bridging-Header.h` を作成
- 全てのファイルを一度に Swift へ移行するとバグやデグレする可能性が高いので、一つ一つ順番に Swift へ移行していく
- `-Bridging-Header.h` を作成して TodayExtension の全てのヘッダーファイルを `-Bridging-Header.h` に書いておく
- Swift にしたものから順にコメントアウトして、最後に `-Bridging-Header.h` ごと削除すれば安全に移行できる

## 3. Swiftにする
- 黙々と TodayExtension のソースを Swift に書き換える
- `-Swift.h` は `-Prefix.pch` に書いておき、objective-c のクラスに import する手間を省く

## 4. `-Prefix.pch` 、 `-Bridging-Header.h` 、 `-Swift.h` の参照先を変更
- TodayExtension を Swift に書き換えた後、`-Prefix.pch` 、 `-Bridging-Header.h` 、 `-Swift.h` の参照先を本体アプリのものに変更する
- 参照先の変更は **TARGETS の TodayExtension > Build Settings > Basic > Combined** から検索すれば、下記の項目がヒットする

-Prefix.pchの参照先 | -Bridging-Header.h と -Swift.h の参照先
--- | ---
<img src="https://qiita-image-store.s3.amazonaws.com/0/37385/1d2b5ef6-de6b-cb06-57ec-7db83af76fbd.png" width="450"/> | <img src="https://qiita-image-store.s3.amazonaws.com/0/37385/95049ba1-6976-943d-ad18-1a1f5d0b53aa.png" width="450"/>


- これで本体アプリと TodayExtension が共通して同じファイルを参照するため、TodayExtension の `-Prefix.pch` 、 `-Bridging-Header.h` 、 `-Swift.h` は不要になる
- これで無事移行完了、お疲れ様でした

# 番外編：TodayExtension の Cell に View がうまく表示されない
Swiftへの移行とは関係ないけど、TodayExtension で少し困ったことがあった。本体アプリで表示したいグラフを TodayExtension の Cell に表示しようとするが、動作が不安定でうまく Cell に表示されない (たまに、うまく表示されたりもするから、やっかいだった)。

TodayExtension のメモリは限られたものしか割り当てられないので、重い処理などは推奨されていない。けど、TodayExtension にグラフを表示したい。そこで、直接グラフのカスタムViewを Cell に利用するのではなく、 `UIGraphicsBeginImageContextWithOptions` で `UIImage` に書き出して、それを TodayExtension の  `cell.imageView?.image` に利用することでうまくいった。

```Swift:GraphView
func image() -> UIImage? {
        
    self.backgroundColor = .clear
    UIGraphicsBeginImageContextWithOptions(self.frame.size, false, UIScreen.main.scale)
    let context = UIGraphicsGetCurrentContext()
    self.layer.render(in: context!)
    let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!

    return image
}
```

```Swift:TodayExtensionのUITableViewCell
self.imageView?.image = graphView.image()
```

最初は `UIGraphicsBeginImageContextWithOptions` の処理が重かったりして上手くいかないかもと思い、`UserDefault` にグラフの画像を保存しておき、 TodayExtension ではそれを利用する方法をとってみたが、そこまでしなくても、直接Viewから、`UImage` を作成して TodayExtension 側に渡すだけでうまく表示できた。

グラフなどの複雑なカスタムViewを TodayExtension に表示したいけど、うまく表示できない場合、`UIGraphicsBeginImageContextWithOptions` で `UImage` にして利用すれば上手くいくかもしれません。