読者です 読者をやめる 読者になる 読者になる

App Extension 上で UINavigationBar.appearance() が HostApp から影響を受ける問題を回避する

ちょっとマニアックな情報ですが、ドキュメントのどこにも書かれていないとっておきのネタです。

Action Extension、またはShare Extensionを開発していて、UINavigationBarを利用しているという方はぜひご覧ください。


この記事は Cocoa Advent Calendar 2016 6日目の記事です。昨日の記事はnaochi___さんの[iOS] Xibを使って自前のダイアログを作るでした。

この記事では、id:kaniza さんの4日目の記事 第 70 回 Cocoa 勉強会関西に行ってきた - kanizaのブログ で触れられている、 第70回 Cocoa勉強会関西 で私が発表した内容について書きます。

"App Extension 上で UINavigationBar.appearance() が HostApp の影響を受ける問題" とは?

このような画面のAction Extensionを作成したとします。以降このTargetを"Action" Extensionと呼びます。

f:id:niwatako:20161204190651j:plain

NavigationBarのBar Tintがオレンジに、DoneボタンのTintが白になっています。

f:id:niwatako:20161204190655j:plain

予定では、このエクステンションを起動するとこのような画面になるはずです。ここで見えているオレンジ色のNavigationBarがこの問題の主役です。

f:id:niwatako:20161204190658j:plain

実際に起動するとどうなるでしょうか。Safari上で試してみます。共有ボタンから開いたアクションシートで今作成した "Action" Extensionを開きます。すると設定通りの画面が表示されます。

f:id:niwatako:20161204190702j:plain

同じことをPocketというアプリの上でやってみます。共有ボタンから "次を使用して共有:" を選んで開いたアクションシートで、"Action" Extensionを開きます。そうすると今度は、NavigationBarが意図した色になっていません。

f:id:niwatako:20161204190705j:plain

これが "AppExtension上でUINavigationBar.appearance()がHostAppの影響を受ける問題" です。

何が原因か

原因は UINavigationBar.appearance() 周りにあります。

Pocket上でNavigationBarが白くなってしまったのは、Pocketが自身のアプリ上のNavigationBarの見た目をカスタマイズするために、UINavigationBar.appearance().barTintColorを白に設定しているため、と考えられます。

f:id:niwatako:20161204190708j:plain

試しにUINavigationBar.appearance().barTintColorを赤にするアプリを自作し、そのアプリからExtensionを起動すると、今度はNavigationBarが赤くなります。

UIAppearanceの設定は、そのアプリ上で利用するApp Extensionにまで影響を及ぼすのです。

f:id:niwatako:20161204190712j:plain

この問題にどうやって対応するのか

この問題を防ぐ方法は、密かにiOS10から利用できるようになっています。App ExtensionのInfo.plistに設定することが出来る NSExtensionOverridesHostUIAppearance キーです。 NSExtensionのDictionaryの中にBooleanでYESを設定します。

f:id:niwatako:20161204190716j:plain

これを設定した "Action" Extensionをもう一度Pocket上で起動してみます。すると、今度は意図した通りのカラーでNavigationBarが表示されました。

f:id:niwatako:20161204190719j:plain

この NSExtensionOverridesHostUIAppearance については、ドキュメントには書かれていません。しかしiOS10から機能します。また、このキーを利用してもAppStoreの審査で問題になることはありません。

UINavigationBar.appearance()がHostAppの影響を受ける問題はShare Extensionでも発生します。Extension上でUINavigationBarを利用している場合は、Info.plistに NSExtensionOverridesHostUIAppearance を追加しておくと良いと思います。

参考

ここのIssueでも言及されています。調査中ステータスのままですが。

github.com

インターネット上で NSExtensionOverridesHostUIAppearance に言及しているサイトはこの記事が2番目のはず...

XcodeのPlaygroundが僕の無茶苦茶なコードを勝手に実行して自滅するので手動実行にして実行ショートカットキーを割り当てた

XcodeのPlaygroundはコードを書いてるそばからその実行結果を視覚的に表示してくれる、インタラクティブなSwiftプログラミング環境です。

f:id:niwatako:20161119014516p:plain

コンパイルが必要なプログラミング言語であるSwiftを、書いているコードに対応付ける形で、処理過程〜結果をリアルタイムに可視化してくれるため、ちょっとコードを書いて試したり、試作を行ったり、視覚効果の調整を行ったりするのに便利です。

けれど、勝手にいろいろやってくれすぎると不便なこともある

僕は、よくわからないコードをとりあえず書きながら考えて理解するのにPlaygroundを使うことが多いです。そういう用途で利用していると、僕が無茶苦茶なコードを書いていて、それを自動で実行しようとしたPlaygroundは自滅してしまう(Macに負荷がかかる処理を実行したり、裏でコードの実行を担っているやつがクラッシュしたり、最悪Xcodeがクラッシュしたり)、という事態によくなります。

書き換えた結果が即時反映されるのがPlaygroundの良いところなのかもしれないですが、実行出来ない・無茶苦茶なのは分かりきっている試行錯誤のカオスコードを無理やり実行して自滅されるのも困るので、自分の用途に合うように何とかしてみます。

普通にManually Runできる

画面下の方にあるRunボタンを長押しすると、AutomaticallyとManuallyを選べます。Manuallyにしておけば自動で実行されなくなります。

f:id:niwatako:20161119012829p:plain

Manually Runを選んだら、次からは実行したいタイミングでこのRunボタンを押せば良いです。デフォルトではショートカットはありません!

...しかし、実行するためにボタン押すの不便ですよね?

ボタン押すのは不便すぎるのでショートカットを設定する

さっきまではお節介なほどに勝手にコードを実行しまくっていたPlaygroundが、今度はいちいちボタンを押さないと実行されない、ショートカットキーもない不便な代物になってしまいました。

アプリ開発中なら コマンド+R キーでデバッグ実行できます。Playgroundも同様にショートカットで実行したいッ!

というわけでショートカットキーを設定しましょう。デフォルトで割当られたキーがないだけで、ちゃんと設定することが可能です。

Preferencesを開いて

f:id:niwatako:20161119013333p:plain

Key Bindingsのタブを開きます。絞り込み検索が出来るので Playground などと入力すると、すぐに Execute Playground という項目が見つかると思います。そいつの右の方の空欄をダブルクリックして、 Ctrl+R など適当なショートカットを押して、割り当てを行います。

f:id:niwatako:20161119013344p:plain

ちなみにアプリのデバッグ実行に合わせてPlaygroundの実行も Command+R にしたい、と思うところですが、 Execute PlaygroundRun は別の操作に対するショートカットという位置づけなので、 Execute Playground には Command+R は利用できないです。残念。。

ともあれこれでひとまず、自動実行を防ぎつつ、実行したくなった時はショートカットで簡単に実行できるようになりました。

AWS初心者がAWSをマスターするための入門構成とそこからのステップを聞いてきた

iPhoneプログラミング勉強会京都に行ってなぜかAWS(Amazon Web Service)についての発表を聞いてきました。

twitter.com

発表内容はApplication Load Balancer に恐ろしいバグが有ったというお話と、Amazonに連絡してリリースまでに修正してもらうという緊張と感動のドラマでした。

twitter.com

AWS初心者がAWSをマスターするための入門構成とそこからのステップを質問

発表の後の質問タイムに、せっかくAWSのプロに質問できる機会ということで、iOSプログラミング一筋でやってきた私は、何から初めて、どんなステップを踏んでいけばAWSを使いこなせるかを聞いてみました。

(※ iOS一筋でやって来たと言えども、Linuxサーバーセキュリティ徹底入門 を読んでサーバー立ててみたり、AWS EC2のインスタンスにログインしたり、ログみて障害の原因調査したこととか、サーバー触った事自体はあるけれど。でもAWSに自分で何か構成したことはない。)

頂いた回答!

EC2とS3の連携をAPIを使ってやってみると、APIを使って他にサービスと連携するというAWSの基礎ができる。それができれば他のサービスとの連携もできる。

ユーザーが画像を投稿するサービスだとして、データベースにユーザーデータを保存して、投稿された画像をS3に保存するとか。そしてロードバランサーを入れてサーバーを増やしたり、CPU使用率が上がったらインスタンスを自動で増やすとかやっていくと良いと思う。

個人でお金をかけずにやるなら、Lambdaとかを使ってちょっとしたアプリを作るとかもよいのではないでしょうか。

なるほど。やっぱりEC2とS3から。

たかがEC2とS3、されど

正直、EC2とS3を使うというのはあまりにもベタすぎると思えていた。ただのサーバーとストレージ。まずなんとなくでも触れそうなのはたしかにこれぐらいなんだけど、それをやったところでなぁ、AWS活用してる感あんまりないよな、VPS触ってるのとかわらなさそう...。と、今まで思っていた。

それが "AWSAPIを使ってAWSのサービス同士を連携させる" ということに意味があるという説明は、ベタ過ぎて力が付かないんじゃないかという不安を一掃して、応用が効く力を身に付けることなのだ、ベタなスタートで十分良いのだという自信になる良いアドバイスをいただけた気がしたのでした。

Instagramのパチもんでも作るか╭( ・ㅂ・)و

せっかく教えていただいたので、ちょっと宣伝

話が変わりますが、質問に回答を下さった原口さんがCTOを務める株式会社シーズでは、キャリア採用を募集中だそうです。

www.seeds-std.co.jp