全てのソースを 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 になった
- TodayExtensionは本体アプリの
-Prefix.pch
、-Swift.h
、-Bridging-Header.h
を参照している - 本体アプリは 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 にチェック |
---|
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 の参照先 |
---|---|
- これで本体アプリと 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
に利用することでうまくいった。
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
}
self.imageView?.image = graphView.image()
最初は UIGraphicsBeginImageContextWithOptions
の処理が重かったりして上手くいかないかもと思い、UserDefault
にグラフの画像を保存しておき、 TodayExtension ではそれを利用する方法をとってみたが、そこまでしなくても、直接Viewから、UImage
を作成して TodayExtension 側に渡すだけでうまく表示できた。
グラフなどの複雑なカスタムViewを TodayExtension に表示したいけど、うまく表示できない場合、UIGraphicsBeginImageContextWithOptions
で UImage
にして利用すれば上手くいくかもしれません。