Swift 3 対応時にハマったString Interpolateについて書きます。
String Interpolateとは?
たぶんあまり聞き慣れないんじゃないかなぁと思います。僕も今回の件を調査するまで英語でなんて言うか知りませんでした。
日本語だと文字列内の式展開
とか式評価
でしょうか。
機能としては単純で文字列を定義する時に他の文字列を入れ込むときに使います。
こんな感じ。
let name = "y_koh"
let message = "Hello, \(name)"
モダンな言語には必ずある機能だと思いますが、Objective-C時代には無かったですよね(遠い目...)。
Swfit 3 対応でどんな風にハマったか
さて、そんなString Interpolateですが、こんなところでハマってしまいました。
画像が表示されない
let image = UIImage(named: "layout_\(name)")
// -> image is nil
ラベルにOptional("hoge")
と表示されてしまう。
let name = "\(tag.name)・"
// -> Optional("誕生日")・Optional("ケーキ")・
これのとても困るところが、落ちないんですよね。Imageがnilでも表示されないだけですし、文字列はOptionalと表示されるだけですし。
なぜそうなってしまうのか
勘の良い人はもう気付いていると思いますが、これはIUO(ImplicitlyUnwrappedOptional)が廃止されたことによるものです。
IUOとはvar name: String!
みたいな書き方のことですね。
SwiftからObjective-Cを呼び出す際にnonnull
、nullable
が付いていない場合もIUOとして扱っていましたがこれも同様にOptional型になります。
Optional型であるということは、つまり、明示的にunwrapする必要があります。
Optional型をそのまま使おうとすると普通はコンパイルエラーになるのですが、String Interpolateを使っている場合はコンパイルエラーになりません。
個人的にはエラーにしても良いと思うのですが、おそらくデバッグ等で使うためにそのまま使えるようにしているのかなと予想しています。実はそんなことなかったというのが後ほど分かるのですが。
これって開発者が気をつけるしか無いの?
さすがにそれは辛いので、何かしら自前実装でも良いのでチェックする機構を作れないものかと思いました。print()
であればグローバルに定義されているだけなのでオーバーライドすればいかようにも出来るのですが、String Interpolateは言語仕様なので無理っぽいです。
色々と調べているとこんな記事が。
Optionals and String Interpolation By Ole Begemann
まさにドンピシャな記事です。
Swift 3.1 will actually actually raise a warning when you use an optional in string interpolation like this because this behavior may be surprising.
Swift 3.1 でワーニングが出るようになるとのことです。これは助かりますね。正直ワーニングだと埋もれがちなので、Swift 3 対応を考えるとエラーの方が嬉しいのですが、これから書く分に関してはワーニングでも十分かもしれません。
こちらのPull Requestで修正されて既にmasterマージされていました。
Extend Optional-As-Any Warning to String Interpolation Segments #5110
またこの現象はバグとしてIssueがあがってました。仕様ではなかったのですね。バグなのでSwift Evolutionには載せる必要はないとLattner氏は言ってるそうです。
https://bugs.swift.org/browse/SR-1882
まとめ
色々と調べた結果、ワーニングが出ないのはバグでそのうち直るという結果でした。今回ちょっと難しかったのがそもそもこの機能何て言うんだっけ?というところです。String Interpolation
という機能名を知っていればもっと早く上記記事にたどり着けたはず。。機能名をちゃんと知っておくことはこういう時に大事だなぁと思いました。