2019年12月7日土曜日

最近のクルマの話

こんにちわ、毎年恒例 pyspa Advent Calendar も今年は2019年となりました。12月7日担当のakisuteです。明日の担当は @rokujyouhitoma です。

さて皆さん突然ですが、クルマは持ってますでしょうか?

持ってない?当たり前ですね。馬鹿みたいに高い税金と車両代金と高速道路通行料を搾取されるだけで何一つメリットありませんから。

それでは皆さん、スマホはお持ちでしょうか?

持ってる?馬鹿にすんな?当たり前ですね。今どきスマホ無いと生活が困難ですね。10年ほど前はどうやって電車の車内で時間を潰していたのかすら、もはや思い出せそうもありません。

そういうわけで、私のブログをわざわざ見に来てくださっている方はIT業界、それもスマホアプリ関連の業界の方が大多数でしょうから、スマホについてはバリバリ詳しいけど、クルマなんて持ってないから何一つ知らないし興味もないよ、という方が多数派を占めてらっしゃるのではないでしょうか。本日はそういう多数派の方向けのお話をさせていただきたいと思います。

さて、皆さんがクルマに何の興味も知識もない前提でお話を進めさせていただこうと思うのですが、それでも平成以降に製造されたクルマにはカーナビとかいう地図とか表示するディスプレイが付いていたり、スマホをBluetoothで接続したりしてカーオーディオを聞いたりできるということぐらいはご存じの方が多い、と私は勝手に信じております。ところが今や元号も令和となりまして、どこもかしこもインフォメーションテクニック的なヤツが幅を利かせる世の中になっておりますゆえ、当然クルマに搭載されているカーナビですとかカーオーディオ的なやつもご多分に漏れず高機能化しています。おまけに最近は自動運転 (=カーナビの現在位置情報や道路情報を車両側が使用したい) ですとか、クルマの走行特性モードの設定 (=車両側の走行特性をUIから操作する必要がある) ですとか、クルマのハンドルについているスイッチからカーオーディオを直接操作したい (=車両側の入力をカーオーディオと連動させなければならない) ですとか、そういう昭和の時代では考えられないような高度な統合処理が必要な機能の搭載がクルマにとってもはや必須となっておりまして、昔のように後付で買ってきたカーナビやカーオーディオに配線すればOK、というわけにはいかなくなってきました。

そこで、ここ2年ほど以内に発売された新車の真ん中に鎮座するディスプレイはカーナビではなくマルチファンクションディスプレイとかディスプレイオーディオとか呼ばれるようになってきておりまして、タッチパネルを装備し、カーナビ、オーディオ、エアコン、車両の設定などを直接タッチ操作で行う高度なシステムに変貌しています。

それだけには留まらず、今年発売された新車に至っては4G接続用のSIMとアンテナが装備されており自立通信が可能で、電話は当然として緊急時の連絡サービスや、煽り運転されたときにボタンひとつで自動的に通報してくれるサービスもあり、カーナビの地図情報の自動更新やシステムアップデートもこなすことができます。なぜクルマにこのようなものが必要かといいますとこれまた将来的に重要になる自動運転が絡んできまして、最新の地図が常に使用されていないと自動運転は危険だからだとか、万一なにか問題があったときに自動運転中の車両を遠隔監視できていないと駄目だとかそういう理由があります。そこで先んじてこのような通信能力をクルマに持たせているというわけです (※おそらくは裏で匿名運転データの収集も行っているのではないかと推測していますが、そのへんは不明です) 。

さらには昨今のスマホ社会を反映し、各社自動車メーカーが用意したスマホアプリと車両が連動して、スマホアプリから現在の自分のクルマの位置を調べるだの、走行距離とガソリンの残量を調べるだの、カーナビに目的地を送信するだの、果ては走行前に社外からエアコンをONにしたりクルマのドアロックをスマホアプリから開けてしまうだのといったことまで可能になっているのです。

どうでしょう、まるでスマホみたいですね。
そのとおり、最近のクルマにはちゃんとしたOSがいます。

このクルマのOSは現在のところ基本的には各社自動車メーカーが内製で作っている (かまたは基本システムだけ買ってきて各社勝手にカスタマイズして使っている) ものが多いようで、iOSとAndroid以外のOSが事実上絶滅したスマホの世界とは異なり、どの会社からクルマを買うかによって大いに出来栄えと機能に差がある状態です。

中にはスマホ世代の我々にはひと目見ただけで開発者をコンクリ詰めにして東京湾に投げ捨ててやりたくなるようなひどい代物も多数存在します。それどころかタッチしてから0.5秒遅れで反応するUIなどといった、初代iPhoneどころかAndroid 1.5 Cupcake世代の産業廃棄物スマホにすら劣るレベルの実装すら、世の中のクルマに存在します。

ヤバいですね。何処のドイツでしょうか、そんなひどいブツを作るのは。実際に見てみたいと思いませんか?

・・・ここで、ちょっと話は変わるのですが。

メルセデスというクルマのブランドがあります。

あまりクルマに詳しくない人でも、ベンツといえば分かるでしょうか。そう、ドイツの高級車メーカーです。最近はメルセデスという名前で名乗っていますので、メルセデスと呼ぶことにします。

でそのメルセデスといえば、皆さん誰でもすぐに高級な外車で、金持ちが乗ってそうなイメージを浮かべると思います。当然、見た目も高級だし、内装も高級だし・・・

・・・車載OSの動作だって高級で高品質を期待します。当たり前ですよね。下手すると1000万円とか払うクルマなわけですから、iPhone 11 Proみたいにきれいな見た目で高速にちゃんと動作することを期待したいじゃないですか。iPhoneなんて10万円かそこらしかしないんですから。

じゃあ見てみましょうか。メルセデス。でもなぜだか知らないんですが日本仕様・右ハンドル・日本語表示のMBUX (Mercedes Benz User Experience) のUI、ネット上にほとんど落ちてないんですよね。しょうがないから実車の写真を撮ってきました。

ネットから拾ってこれた左ハンドルでの画像ですが、横一列につながった超ワイドなディスプレイ、一見なかなかカッコいいですね。高級感もあるし、これは期待できるのでは・・・

って思った?残念!半角カナちゃんです!

見ての通り、細部に至るまで半角カナです!

 こっちは半角カナじゃありませんがガソリンスタン...になっちゃってます。

幸いにしてタッチパネルの操作感度はまぁまぁ良好だし、タッチしてから1秒以上固まるみたいな絶望的な遅さは無いのですが、どう見ても初代iPhone 3Gとドッコイドッコイ程度の動作速度しかありません。そもそも走行中にカーナビを操作したくなったら、身を乗り出してこのタッチパネルを手で触れというのでしょうか?まことに素晴らしいUXだと思います。

引用元: https://www.elasticfeed.com/44db3e868b3b3bfe82835c65441ea3ca/

もちろんそのような危険なことをしないで済むように、こうして中央手元にMagic Trackpadもどきが付いているのですが、手触りはともかくこいつの反応が10年前のWindowsノートパソコンのほうがマシなのではという次元でして、自分のmacに触れた後にこいつに触ると引きちぎって車外に投げ飛ばしてやりたい気分に駆られること間違いありません。設定で感度を調整したりもできますがどう調整してもイライラするので、結局中央のタッチパネルを身を乗り出して触るほうがマシだったりします。

その他、ハンズフリー操作のために音声アシスタント、いわゆるSiriもどきがついてるのですが、社内での会話中にうっかり「メルセデス」という単語を口にした瞬間「なにか御用でしょうか」と起き上がってきて大変邪魔です。名前を呼んではいけないあの人扱いみたいになっています。しかも初代のSiriより頭が悪く、基本的に何お願いしてもマトモに対応してくれないので使えません。お願いだからOK Googleと席を変わってほしくなります。



極めつけはカーナビです。なんとこちら1年近く道路情報が更新されていないようで、設定画面から最新状態に更新しているにもかかわらず半年前に開通した道路が地図上に存在しません。当然カーナビはそこを迂回しようとします。全く使えません。メルセデスの人に聞いてみたところ、現在地図データを頑張って作ってるらしいです。頑張ってくださいね。

ちなみにこちら、お見せしましたのはAクラスといいます一番安物のメルセデスですが、実は2000万円以上するメルセデス・マイバッハと言われる最上位車種でも全く同様のMBUXが使用されています。それどころかAクラスは今年モデルチェンジされたため、下手するとそれらよりも最新のOSが搭載されています。要するに2000万円以上する超高級車でも1年前の道路しか存在しないカーナビを使わされるというわけです。まぁ、そんなクルマを買うような人は自分で運転なんかしないでしょうから、何の問題もないのかもしれませんね。

じゃあ、次はメルセデスのスマホアプリを見てみましょうか。

まぁ悪くはないですね。

なんかWebViewっぽい匂いがしますが・・・

一応ネイティブアプリのようです。FOSS (Free/OpenSource Softwares)をちゃんと列挙しているのは好感が持てますね。

一応機能は充実してますね。

見ての通りクルマのドアロックをこのアプリから開けることもできます。

カーナビ連動もありまして、この画面から目的地を検索してクルマのカーナビに飛ばすことも可能なのですが、

見ての通りこの程度の検索すらロクにできませんので使い物になりません。まぁよしんば目的地がクルマに送信されたところで1年前の日本地図に基づいてナビゲーションされてしまうので、どっちにしろ使い物にならないと思いますが。

いかがでしたでしょうか。まぁ、車載MBUXに比べると幾ばくかマシかもしれませんが、2000万円以上払った人専用アプリなんてものはございませんので、最廉価のAクラスユーザーでも最上位のVIPユーザーでもこのアプリを使わされることになります。もうちょっと頑張れよと思わないでも無い気がします。

一応、弁護させていただきますと英語版やドイツ語版は半角カナではないのでフォントはマシですし、多分ドイツにサーバがあるのでドイツで使ったほうがアプリの動きも多少はサクサクだと思いますし、ドイツ国内のカーナビは多分1年遅れで更新されるとか言うことも無いはずです。要するに日本版が飛び抜けてショボいだけかもしれません。あとクルマ自体は普通にとんでもなく良かったので、アプリとか気にしない人にとっては最高のクルマだと思います。

で。
また閑話休題で申し訳ないのですが。

テスラというクルマのブランドがあります。

最近話題になることが多い電気自動車のメーカーです。あのイーロン・マスクの会社というと我々IT業界人には通じやすいのではないでしょうか。何かやってくれそうな気がしませんか?

そのテスラなんですが、こんな感じなんです。

iPad Proより巨大なタブレットのようなサムシングが鎮座しています。

引用元: https://response.jp/article/2019/08/19/325526.html

見てください、これ。まるでiPadのアプリにしか見えません。このテスラ モデル3の社内にはハンドル周り以外に一切の物理ボタンが存在せず、ディスプレイもダッシュボードのメーターもありません。速度計の確認も、エアコンの操作も、ハンドルとアクセルとブレーキとギアの選択とウィンカー操作以外、何もかもすべてこのiPadで行うことになります。

普通にメチャクチャ綺麗です。カーナビに至ってはおそらくこれGoogle Mapsそのものです。当然、Google Mapsですから、1年前の日本地図が表示されることもなければ、パチンコガンダム駅が存在することもありません。完璧に最新最先端の地図が無料でいつでも使えます。素晴らしいですね。

では、テスラのアプリはいかがでしょうか?

当然のようにネイティブです。まぁReact NativeかもしれませんしFlutterかもしれませんが。




どうみても出来が良いです。半角カナなんて汚物は当然存在しません。

これで、テスラ モデル3の車両価格は最高でも717万円、最安値ですと511万円で収まります。

以上で大体私の申し上げたいことはなんとなく伝わってきたのではないかと思います。つまり、我々スマホ開発者界隈が買うべきなのはテスラってことです!さぁ、このテスラの新車を今すぐ予約してあなたも未来を体験しましょう!



・・・やっぱりメルセデスのほうがいいですね!メルセデス最高!



最後に余談になりますが、Apple CarPlayとAndroid Autoについてちょっと話します。この2つはスマホ開発者界隈の皆様も少しくらいは聞いたことがある名前ではないでしょうか。これまで見てきましたとおり、最近のクルマには車載OSが存在するのですが、Apple CarPlayやAndroid Autoは車載OSのアプリの一つとして動作します。要するに車載OSのナビアプリを開いたりオーディオアプリを開く感覚で、CarPlayアプリを開いて、その中でCarPlayのUIの中で更にiOSのアプリを操作する、みたいな作りになっています。

引用元: https://www.elasticfeed.com/44db3e868b3b3bfe82835c65441ea3ca/

そのせいで、見てのとおりに画面が狭いです。どうやらApple Carplayは7インチの画面を前提に作ってあるようで、10インチのワイド画面であるメルセデスのディスプレイオーディオにはフィットしません。しかしながらこの中は完全にiOSであり、マトモなGoogle Mapsが機能します。おまけにスマホと車体が連携しており、車体側から車載GPSやジャイロコンパスなどのより正確な情報を提供してもらえるため、スマホ上で使うGoogle Mapsより段違いに自車の現在位置精度が高くなります。

参考: https://developer.apple.com/documentation/carplay
参考: https://developer.apple.com/design/human-interface-guidelines/carplay/interaction/car-data/

なんかクルマ向けにアプリ作ってみてえなと言う人がいらっしゃいましたら今がチャンスかも知れませんのでぜひぜひやってみていただければと思います。まぁ、デバッグに実車が必要・・・かもしれませんけど・・・

最近は国産車でもトヨタ・カローラという昭和のジジイ以外だれも知らないようなオワコンカーがびっっっっっっっっっっくりするぐらいモダンで素晴らしいクルマに生まれ変わりまして、そちらの新型トヨタ・カローラには標準でカーナビがついておらず、Apple CarPlay / Andriod Autoやトヨタ独自のSDLという規格を利用してスマホをナビにすることを前提の作りになっています。まさに今のスマホ時代にふさわしい素晴らしい方針だと思います。

2019年9月24日火曜日

SwiftUI で ScrollView / Listの現在のスクロール位置 (UIKitにおけるcontentOffset) に相当する値を参照する/コード上から指定する方法は iOS SDK 13.0 地点では存在しない

タイトルの通りですが一応補足しておきます。

先日、奇しくもAppleのSwift UIを実際に手掛けている開発者に直接質問する機会に恵まれましたので以前から気になっていた内容を質問してみたのですが、やはり現段階のリリースではcontentOffsetに相当するものの変更タイミングを取得したり、またプログラム的にcontentOffsetを調整することもできないと明言されてしまいました。

ただしcontentOffsetの変化したタイミングを取得するだけであれば、以下の方法で擬似的に再現することができるとアドバイスを頂きました。


  1. ScrollView / List 上の特定の位置に、ダミーの隠しViewを配置する。
  2. 隠しViewのonAppear() / onDisappear() を利用する。


彼曰く、コミュニティの誰かが作ったサンプルのVideoPlayerアプリがこのテクを使って動画が画面内に入ってきたときに自動再生を開始する挙動を実現していると言っていたのですが、具体的にどのサンプルアプリなのかは教えてもらえなかったので発見できず。残念。

あとは例によっていつものごとく、機能追加が欲しい場合は https://developer.apple.com/bug-reporting/ 経由で要望を上げてくれると対応できるよと言っていましたので皆さんガンガン書けばいいと思います。

2019年6月8日土曜日

SwiftUI 未解決問題まとめ

一通り試してほぼほぼ理解できたのですが、現状どこをどのように調べてもわからなかった内容がいくつかあるので未解決問題としておいておきます。誰か教えて\(^o^)/

Transition

type-eraseされたAnyTransitionはSwiftUI.frameworkに居るのですが、元のProtocolが見えない上にドキュメンテーションも一切ありません。おそらくはNavigationViewの中で使われているのだと思いますが詳細不明。

ScrollView / Listの現在のスクロール位置 (UIKitにおけるcontentOffset) に相当する値を参照する/コード上から指定する方法

今の所、一番怪しいのが以下のpreferenceの仕組みではないかと睨んでいるのですが、
問題は肝心要のPreferenceKeyの具体実装がSwiftUI.framework上には一切見つからず、したがってキーが指定できないためonPreferenceChange(_:perform:)がうまく利用できません。特定位置までスクロールしたら発火、とかビューが50%スクロールして隠れたら発火、とか普通に使いたいのですが、困りました。それとかあとはenvironment経由なりイニシャライザ経由なりでinitialScrollPositionのようなプロパティを用意してScrollViewのスクロール初期位置を与える、みたいなテクも使いたいですし、普通に必要だと思うんですけど(´・_・`)

ちなみにView.offsetではない・・・と思います、たぶん。一応念のためにList.offset()で試してみましたが、ドキュメンテーションにもある通り、全く違う挙動になります。

SwiftUI チュートリアル ヘルプ ドキュメント FAQ 困ったらとりあえずここ見ればOK

https://github.com/Juanpe/About-SwiftUI

いろいろ調べたのですが、これよりよくまとまっているドキュメントを現状発見できませんでしたので、2019/06/08現在では上記のドキュメントを参照するのがベストだと思います。

特に以下の記事は役立ち度が高かったです。この2つだけで問題の9割ぐらいは解決できると思います。

SwiftUI by Example
https://www.hackingwithswift.com/quick-start/swiftui

Answers to the most common questions about SwiftUI
https://wwdcbysundell.com/2019/swiftui-common-questions/

あとは直接SwiftUI.frameworkの中身を見るのが良いと思います。正直Appleのドキュメンテーションは未だにSwiftのExtensionベースの実装をきれいにドキュメントに起こす事ができておらず、複数のドキュメントに重複した記載が見られたり、どこで定義されているfunc/varなのかを正しく表現できていなかったりします。なのでシグネチャの名前さえわかっていればSwiftUI.frameworkの中を自分で検索したほうが正確にどういう定義になっているか判断できて便利です。

2018年12月19日水曜日

HTML5 video / audioがiOSデバイスの消音スイッチの状態に従うようにする方法 (UIWebView編 / WKWebView編)

いろいろ調べていたのですが、遥か大昔に私が書いたブログ記事が長い年月を経て今や大間違いになっていたのでここに訂正させていただきたいと思います。

今回ご紹介するのはUIWebViewまたはWKWebViewで表示しているHTML5のvideo要素やaudio要素が音声を出すときに、iOSデバイスについている消音スイッチ (ミュートスイッチ, mute switch, silent switch) の状態を無視してしまう問題を解決する方法です。相変わらず紹介内容がとてもニッチですね。

ちなみにSafariはデフォルトでちゃんと消音スイッチの状態を反映してくれるので、SafariでYouTubeの動画を見ててもいきなり音が流れ出すことはありません。素晴らしい!というわけで我々のアプリもぜひそのようにしたいと思います。

消音スイッチの挙動について

まず基本的なおさらいとして、消音スイッチがどのような挙動を示すかについてこちらにまとめます。
  • 各プロセスごとに、AVAudioSessionが消音スイッチに対してどのように振る舞うかを定義している。
  • 具体的には、AVAudioSession.Categoryの値に応じて挙動が変化する。ドキュメントにも明記されている。
    • AVAudioSession.Category.ambientやAVAudioSession.Category.soloAmbientを指定すると、消音スイッチがONのときは音が出ないようになる。
    • 逆にAVAudioSession.Category.playbackを指定すると消音スイッチを一切無視するようになる。
  • 消音スイッチの現在の物理的な状態を取得するAPIは一切ない。Private APIで以前は可能だったが、穴が塞がれたためその方法も利用できない。そもそもアプリが提出時の審査で蹴られる。当然JS経由でHTMLコンテンツ上から状態を取得するのも不可能。

解決方法・UIWebView編

UIWebViewはWebKit1を利用しており、したがってUIWebViewのエンジンは我々のアプリ内のプロセスで動作します。そこでUIWebViewのインスタンスを生成するより先に、先述の通りAVAudioSessionのcategoryを変更して消音スイッチの状態を反映してやるように示してやるとうまくいきます。
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default, options: [])
try? AVAudioSession.sharedInstance().setActive(true)
ただしご存知の通り、すでにUIWebViewはdeprecated扱いとなっており、WKWebViewへの移行が推奨されています。そこでWKWebViewでも同様の方法が使えないかやってみましょう。

解決方法・WKWebView編

ありません。

繰り返しますが、ありません。WebKit2の設計上のバグです。

今後修正される可能性もほぼ間違いなくありません。諦めてください。

一応、順を追って説明します。
  1. WKWebViewはWebKit2で実装されています。
  2. WebKit2は我々のアプリ内のプロセスで動作するのではなく、「共用の」WebCoreプロセス上で動作し、その結果が我々のアプリ内に転送されてくるような実装になっています。
  3. 「共用の」WebCoreプロセスは(これは推測ですが、audioやvideoを最大限に活かすため)AVAudioSession.Category.playbackとAVAudioSession.Mode.moviePlaybackで動作するように設定されている用に見えます。したがって消音スイッチは無視されます。
  4. 最初にご説明したとおり、AVAudioSessionによる消音スイッチに対する振る舞いは「プロセス単位」で制御されており、これは遥か大昔のiOS 2.0どころか下手するとNeXTSTEPの時代からCarbonレイヤーで決められている挙動だったりします。要するに今からの変更はほぼ不可能です。
  5. もうおわかりだと思いますが、「共用の」WebCoreプロセスの挙動を我々個別のアプリがAVAudioSession経由で勝手に変更することは不可能ですし、これを可能にするのはiOSとWebKitの設計上実質不可能なため、問題は解決されません。
    1. WebCoreプロセスを各個別のアプリごとに立ち上げて対応しろよ!と思うかもしれませんが、WebCoreプロセスは近年AppleのOSに組み込まれている特権階級モードで動作するプロセスとなっており(そのためメモリに無制限なアクセスが可能で、JSをJITコンパイルして高速に動作させる事が可能)、最近のセキュリティとバッテリーライフにうるさいAppleがそれを個別のアプリごとに立ち上げさせるなどということは現経営陣が全滅しない限りありえないと断言できます。
    2. 共用のWebCoreプロセスが使用するAVAudioSession.Categoryを変えてしまえばいいだろ!とも思いますが、実はAVAudioSession.Categoryをplaybackに指定しない限りバックグラウンドで音楽を流し続けることができません。したがって今度はWebViewで音楽プレイヤーを作ったりPicture in Pictureで動画を流し続けるアプリが全滅するため、これも不可能です。
    3. だったら消音スイッチの状態を自分で調べて自分で動画をmuteにすればよいのでは、と思いますが、これも先述の通り消音スイッチの状態を調べる方法は一切ないため、一律でmuteにしてしまうなどの乱暴な方法を用いない限り対応できません。
やばいですね☆

iOS開発でエラーコードを調べるときはOSStatus.comを使おう

久しぶりに書く価値のあるネタが見つかったのでご紹介します。

iOSのフレームワークがNSErrorを返してきたとき、そのcodeが何を意味するのかを調べる必要が出てくることが往々にして発生します。新し目のフレームワークは比較的簡単に調べられるようにまとまっているのですが、厄介なのがOSStatusなどの大昔から存在するエラーコードの場合です。

NSError コードの調べ方 こちらのブログ記事で紹介されている通りに一つ一つヘッダファイル内を探す方法でもいいのですが、もはや平成の終わりが目の前に迫っている2018年の年の瀬にもなってこのような原始的な方法を使っているようではよろしくありません。

そこで OSStatus.com の出番です。こちらの検索欄にcodeをコピペして検索ボタンを押すだけであらゆるエラーの詳細が一発で帰ってきます。実際にやってみましょう。


一発ですね。素晴らしい。


名前での検索もバッチリです。

偶然見つけたのですが、はてブもほとんどついてないし、ネット上で紹介されている記事も全く見つからなかったので書いてみました。便利です!

2018年12月1日土曜日

2018年のしめくくり

pyspa Advent Calendar 2018 12/1です。

早いもので、あっというまに2018年も終わりを迎えそうな時期になってまいりました。皆様ご無沙汰しております、akisuteです。今年もまとめだけ書いて終わりにしたいと思います。

今年やったこと

JavaとかSwiftとかKotlinとかNode.jsとかReact Nativeとかやってました。Node.jsはなかなかいいですね。食わず嫌いで最近まで手を出しておらず、昔はお手軽になにか作りたいときはもっぱらPythonだったのですが、今ではついついNode.jsを使うようになってしまいました。特にTypeScriptが大変気に入っております。

細かいところですとチームのドキュメンテーションの問題を考えている時間が増えてきました。というのも最近ようやく気づきを得たのですが、プログラマの中にはドキュメンテーションができるタイプの人と一切できないタイプの人の二種類がいるように思えます。後者のタイプの人がドキュメンテーションが不得手な理由を自分なりに考えていますが、
  • 「自分が理解しているので、相手も理解しているだろう、相手も理解できているだろう」という考えがあり、そのため本来必要であるドキュメントが不用と判断されて欠落してしまう。
  • 思考が直接コードで行われているために、わざわざ日本語なり英語なりの言語に変換されない。またはその変換コストがその人にとって高い。
  • 間違った情報ということは認識しているのだが、既存のWikiやコードコメントを書き換えるのを遠慮してしまう。
これらが原因なのかどうか、いずれも定かではありません。テンプレートを整備してみたり、OpenAPI+ReDocのような解決策に頼ってみたりしているのですが、なかなか成果が上がっておらず。ドキュメントが不足しがちな人をあえてドキュメントが必要な状況におく(普段とは違うプロジェクトをアサインして、ドキュメントを読まなければにっちもさっちもいかない状態にすることで、どのような情報が欠落すると自分が困るのかを理解できる)とかはいいアイデアなのでは?と思っています。ドキュメンテーションの得意な人と組ませて、得意な人がレビュープロセスなどで書き加えるというアイデアなどもなんとなく回りそうな気はしています。なかなか難しいです。

今年のGotY

Forza Horizon 4以外にありえないですね。これより優れたクルマゲームは地球上に存在しないと断言していいレベルで素晴らしいです。RDR2は正直雰囲気と世界観のためにゲーム性を犠牲にしすぎている気がします。1ほど楽しめませんでした。どうやら私もおっさんになったようです。

今年のマイブーム

Forza Horizon 4のせいか急にクルマがマイブームになってきました。と言っても別に今すぐクルマを持ちたいとは思っていません。なにせ現実世界のクルマはカネがかかり、乗っても楽しく乗れる場所はなく、ただひたすら渋滞とマナーの悪いドライバーに憤慨し、事故とスピード違反に怯えながらほそぼそとアクセルを踏まなければならないような代物です。全く執着するに値しません。
しかしながらゲームの中となると、たかだか1万円で何百車種もの好きなクルマに好きなだけ乗ることができ、キレイな風景や楽しいコースを好き放題乗り回し、渋滞もなく、マナーの悪いドライバーは遠慮なくポルシェ・カイエンターボで粉々に踏み潰すことができ、事故ったところで現実世界の私はかすり傷一つ受けることもないため何のリスクもなくクルマの限界に挑戦できます。まさにクルマの楽しい箇所だけをすべて味わい尽くすことができるのです。うーん、仮想世界って素晴らしいですね。

まとめ

今年も平和でいい年が過ごせて100%満足しています。よかったです。
来年も平和で良い年でありますように。

2017年12月4日月曜日

2017年のしめくくり

pyspa Advent Calendar 2017 12/4です。

どうもお久しぶりです。オンライン上では一切活動しておりませんが、おかげさまで大変元気にやってます。というわけで2017年のまとめを書いておこうと思います。

そもそもなんで最近ブログ書いてないの

書くことがないからです。というのも私は最近iOS/Androidの開発ではなくジャバでサーバサイドアプリケーションを書くみたいな仕事をしていて、別にSpring Bootの話なんかここに書いてもあまり面白くもなければ、すでにありとあらゆる先人が地雷を踏み尽くしていて調べればだいたいなんでもわからないことは分かる状態になっているので、わざわざ私が書く必要もないと思われるためです。

なんでiOS/Androidやってないの

端的に言えば愛想が尽きました。iPhone Xは買っていません。SwiftとKotlinは大好きで今でも仕事で使ったり他人のコードをレビューしたりする毎日ですが、もはやiOSもAndroidもどちらも執着するには値しません。

なんか技術的に新しいネタないの

正直今ネイティブアプリに大きな流れはないので(ARとクライアントサイド機械学習程度しか新規性のあるネタがなく、どちらも適用分野が限られ、ほとんどのアプリケーションでは縁がない)、後数年の間はモバイルネイティブアプリ一択だった流れが半分ぐらいウェブに返ってくると思っていて、ゲームなどではすでにその兆候もありますし、React NativeとかモバイルフロントエンドJavaScriptとかを見ておけばいいんじゃないのかなぁと思っています。個人的にはあんまりどちらも好きじゃないんですが、悪いものではないと思います。
また、Rxはもはや使えて当然と思っていますが、しかしながらRxを限界まで酷使するようなアプリはごく少数の人間しかメンテできなくなり、そのうちメンテがおぼつかなくなり、Rxのシグナルやオブザーバを使うのではなく昔ながらのdelegateやcallbackで手っ取り早くコードを修正するような事態が訪れ、ゆっくりと破綻していくような事態が周囲で散見されています。正直人間のほうが技術側に追いついていないというか。使えるやつは使えるんだけどそれじゃメンテ回らないよというか。

なんか注目のビジネスネタないの

フィンテックはガチだと思います。儲かるので。ただしビットコイン、というかブロックチェーン技術を神聖視するのは正直イケてないと思います。
動画配信系もガチだと思います。これもカネの匂いがします。ただしこっちはそもそもプレイヤーになれる存在が非常に限られており、ドワンゴすらそろそろもうついていけないかなぁという状態ですので、皆様がんばってくださいという感じです。
AIが〜とか機械学習が〜とかはやらなくてはならないのは間違いありませんが、ぶっちゃけ現状ではまだそんな言うほど大したことないです。どっかのタイミングで私みたいな何もわからないド素人でも簡単に放置してデータ食わせるだけで勝手に最良の状態に学習する事ができるような仕組みが誕生すると思っていて、そうなったら本当に爆発的に世界が変わる気がしています。それまでは自動運転みたいなカネが突っ込まれまくる分野でのみ世界が変わるほどの進展が見られるんじゃないかと勝手に思っています。
スマートスピーカーは正直使ってみて要らないと思います。不便とは思いませんが、現状無くてもほとんど全く困らないので要らないです。無いと困るようになったら爆発的に売れるのではないでしょうか。

今年のゲームはどうだったの

ゼルダがGotY 2017なのは間違いありませんが、その他も非常に豊作な一年だったと思います。個人的な推しはtheHunter: Call of the Wildです。

家どうなったの

友人が家を探しているというので色々物件を紹介していたら、まさかの我がマンションに引っ越してきました。おかげさまで大変楽しい毎日です。近所付き合いってのも悪いもんじゃないと思います。
あとはベッドを買い替えました。こちらもiPhone Xを買うより100倍ぐらい幸福になりました。良いお金の使い方をしたと思います。

婚活どうなったの

退会しました。1年間、のべ数百人単位の女性を紹介してもらって、数十人単位と付き合って、数人とじっくり時間を過ごしてみた得た結論は、正直私は女性と付き合っても煩わしいばかりで楽しくないし、相手も私といても満足できないし、結婚してもいいことはないというものでしたので、そのようにしようと思います。1年前はちょっと焦りとかもありましたが、今では大変気分も落ち着いて平穏が得られました。自らの人生について考える良い機会だったと思います。

今どうなの

おかげさまで非常に幸福な人生を送っていると思います \(^o^)/
来年もいい年になりますように!

2017年6月19日月曜日

UIWebView, WKWebView 等において Drag and Drop を禁止する方法


iOS 11よりDrag and Drop APIがUIKitに追加され、UITextView / UITableView / UICollectionViewに簡単にDrag and Dropを実現するためのdelegateが用意されたり、それ以外のUIViewにもDrag and Dropをハンドリングするための仕組みが用意されました。このDrag and Dropは基本的にはアプリをまたいでデータを受け渡しすることを前提として作られていますが、一応は自分のアプリ内でデータを移動したりコピーしたりするためにも使えるようになっているので、積極的に活用していきたいところです。

ところでこのDrag and Drop、基本的にはアプリ側が対応しない限り自動的には対応してくれないのですが、例外があります。それがUIWebView / WKWebView / SFSafariViewController要するにWebViewのたぐいの皆様です。これらについては最初からDragも可能ですしDropも可能なように作られているようです。便利ですね!

ですがここをご覧になっている皆様の中には、大人の事情によりどうしてもそのような便利な機能をユーザーさんにわざと提供したくないと言うケースがある方もいらっしゃるかと思います。そこでUIWebView / WKWebViewのデフォルトのDrag and Dropを無効化したり、頑張って自分のコードでハンドリングしたりすることができるようにする方法をご紹介します。なおSFSafariViewControllerに対しては手も足も出ないのでご了承ください。
if #available(iOS 11.0, *) { 
    webView.scrollView.subviews.first?.interactions = []
}
たったのこれだけです。簡単ですね!

なんのこっちゃなので詳しく説明します。

まずはじめにiOS 11よりUIView.interactionsプロパティが追加になっています。このinteractionsは[UIInteraction]型となっていて、公式のドキュメントによると「ジェスチャベースの挙動をビューに定義する」ことができるらしいです。まさにドラッグ・アンド・ドロップ的なやつですね。
で、Appleによって最初からドラッグ・アンド・ドロップ用のUIInteractionすなわちUIDragInteractionとUIDropInteractionが用意されています。これらのInteractionは内部的にdelegateを持っていて、これらのInteractionがインタラクションを検知したらdelegateにメッセージングを行い、そいつらが実際のドラッグ・アンド・ドロップ処理を行うというような仕組みになっているようです。
調べてみたところUITableViewのような最初からDrag and Drop用のdelegateを追加されているViewについても、このinteractionsに何らかのUIDragInteraction / UIDropInteractionが追加されていて、それが一旦イベントを拾ってから我々が定義したUITableViewDragDelegate / UITableViewDropDelegateに問い合わせを行うという仕組みで動作しているということがわかりました。

ここまで分かれば後は簡単で、UIWebView / WKWebViewも同様にinteractionsで一旦イベントを受け取った後に、内部的に処理を行っていると考えられるのでUIWebViewの中身をどったんばったん探してみたところwebview.scrollView.subviews.firstの中にinteractionsが刺さっているのを発見したと言う次第です。

先程の無効化する例では空配列を渡すことで完全にinteractionsを無効化していますが、ここで自分が作ったカスタムのUIDragInteraction / UIDropInteractionを渡してやればうまい具合に自分でWebViewのDrag and Drop挙動をカスタマイズすることができるかもしれません。また両方を消すのでなくて片方だけを消せばDragによってデータを持ち出すのは禁止するがDropによってデータを持ち込むのは許可するみたいなこともできます。

2017年5月24日水曜日

Xcode 8.3 & Swift 3.1 環境で LLDB を使う Tips

以前も似たような記事書いた気がするんですが、定期的にSwiftのコード上でLLDBを使ってて困ることがあるので定期的に書くことにします。ほとんど https://stackoverflow.com/questions/29441418/lldb-swift-casting-raw-address-into-usable-type からの転載です。

LLDBの言語を指定して実行する

標準ではbreakpointを挟んでbreakした行がSwiftであればSwift、Objective-CであればObjective-CでLLDBの言語が選択されるようなのですが、これでは毎回毎回breakした地点に応じてデバッグの仕方が変わって大変で仕方がないので、Swiftに統一してしまうのが良いと思っています。
expr -l swift -- {Swift Command}
e -l swift -- {Swift Command}
とすると常にSwiftでLLDBに対してコマンドを送る事が可能になります。逆にObjective-C側に寄せたい場合は
expr -l objc++ -O -- {Objective-C Command}
e -l objc++ -O -- {Objective-C Command}
とすれば良いです。-Oオプションがないと結果がいい感じにObjective-Cのオブジェクトとして扱われないので注意。

importを忘れずに

以前も書いた気がしますがLLDBでbreakした環境はそのままだとFoundation.frameworkすらまともに使えない(シンボルを認識しない)状態なので、importを忘れずにしましょう。
e -l swift -- import UIKit
e -l swift -- import MyApp
e -l swift -- import MyAppLib
という具合でしょうか。他必要なものがあればその都度。注意点として自分のアプリ自体に含まれるシンボル、例えばAppDelegateだとかViewControllerのたぐいだとかもimportしないと触れないので忘れないように。

unsafeBitCast(_:to:)を使ってポインタからオブジェクトを取得する

これも以前書いた気がしますが、Swift 3でまたシグネチャが変わったらしいので念のため。
e -l swift -- let $obj = unsafeBitCast(0x00000000, to: MyClass.self)
e -l swift -- print($obj)
とかやるといい具合になります。

エイリアスを作ろう

毎回e -l swift -- とかタイプするの面倒ですし、poがe -O -- のエイリアスなのと同様に、eswiftとかpswiftとかそういうエイリアスを作ってしまえばいいと思います。~/.lldbinitの中に、
command alias eswift e -l swift -- 
とか書いておけば良い気がします。

2017年3月7日火曜日

NSAttributedString に lineSpace を付与したとき、1行であるにも関わらず lineSpace が下端に付与されて困っている人はこれを読んだら直ります



突然ですが皆さん、NSAttributedStringには2017/03/07付のiOS 10.3現在でも致命的にバグっている箇所があります。

症状:

  • NSAttributedStringにNSParagraphStyleAttributeNameを利用してNSParagraphStyle経由でlineSpaceが付与されている。
  • NSAttributedStringに複数の「区間」が存在する。例えばNSAttributedString全体が単一のAttributeによって構成されているときはこの問題は発生しません。2つ以上の異なるAttributeの区間が必要です。
  • NSAttributedStringを描画するときに、横幅及び文字列の長さの都合で、1行で描画される。複数行になるときにはこの問題は発生しません。
  • NSAttributedStringにNSBackgroundColorAttributeNameが付与されていない。または、NSBackgroundColorAttributeNameとNSKerningAttributeNameの両方が付与されている。

上記の条件を全て満たすとき、
本来、1行の文字列はレンダリングしたときに下端にlineSpaceが付与されてはいけませんが、この条件が満たされていると下端にlineSpaceが付与されてしまいます。先頭の画像の左上のケースがこの問題に相当します。

具体的な問題としては、
  • 問題が発生するNSAttributedStringを使用したUILabel, UITextField, UITextViewの描画内容が思いっきり上にずれます(下に無駄なスペースが発生するので)
  • NSAttributedStringの地点で壊れているので、Core Textを利用したり、boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRectを使っても一切回避できません

解決策: 

この問題に対する正しいワークアラウンドの方法は一つしかありません。

NSAttributedStringの全Attribute区間にNSBackgroundColorAttributeNameを付与し、かつどの区間にもNSKerningAttributeNameを付与しない。

背景色が不要の場合はUIColor.clearでも付与してごまかしてください。
以上です。よろしくお願いします。

参考:

2016年12月13日火曜日

Instruments を使っていてシンボルが見えないときの対処法

Instruments を久しぶりに起動して Time Profiler を使おうとしたら、びっくり仰天シンボルが全部見えない状態になっているじゃあありませんか。 Swift化したのがあかんのか!?と思って調べてみました。

結論から言うと、先日ビルドの軽量化のためにDebugビルド時にdSYMの出力を止めていたのが原因でした(´・_・`)
http://stackoverflow.com/questions/36882788/how-to-create-dsym-file-in-xcode-7-0
Debug Information FormatをDWARF with dSYM Fileに戻して、dSYMの出力を再開したら問題なくシンボルが出力されるようになりました。なんじゃそりゃ。

それでもだめな場合はInstruments側のFile -> Symbols... を選択すると、直接モジュールのdSYMを指定する事が可能になります。覚えておくと便利かもです。
http://stackoverflow.com/questions/33683690/apple-instruments-has-mangled-symbols-and-greyed-out-symbol-names-when-profiling

2016年12月1日木曜日

pyspa Advent Calendar 2016 1日目: 今年の話

去年に引き続きまして pyspa Advent Calendar 2016 一番槍担当の斧さんakisuteです。よろしくお願いします。

去年はゲームの話をしましたが、今年は人生に一度しかやらなさそうなイベントを大量に発生させましたので、主に今年何をやっていたのかについてご報告させていただきたいと思います。

1. 家を買いました

ずっとワンルームのアパートにしか住んだことがない男だったのですが、30過ぎたので人生一度きりだし家でも買ってみるかと思い、半年ほど探して思い切ってタワーマンションの部屋を買ってしまいました。

正直ちょっと前まで家を買うとか単に負債を抱えるだけの大アホだと思っていたのですが、実際に買ってみると案外悪くなかったです。売ればいいとか資産価値があるとか賃貸より買ったほうが割安とかそういうことはさんざん世間様がおっしゃってるかと思いますので、ここではあんまり世の中では言われていない気づきを書いてみようかと思います。

買うと(当たり前だけど)自分のものになる

賃貸で引っ越しするのとはまるで違う感覚です。まず引き渡しですが鍵と権利書をもらうだけです。クリーニングすらされてません。売主は貸主様じゃないので当たり前です。そこでハウスクリーニングを自分で呼んで掃除してもらい、あとは業者を呼んで鍵を付け替えてもらったりします。なんというか、自分のものなんだな、今まで家を借りてた相手の家主さんというのはこういうことをやってたのかな、という感じがします。

当然(マンションの管理規約の範囲内で)部屋は自分のものなので、壁に穴を開けようがぶち破ろうが工事してみようが全て自由・自己責任となります。逆に老朽化した設備を保守点検するのも自分の責任となります。とにかくなんというか、守るものができたなぁという感じを大いに受けます。

売買は意外と大雑把

私の場合売主さんが全ての鍵を渡すのを忘れてましたというのが後から発覚して大騒動になりました。最終的には無事全部私の手元に来たのですが、大手の不動産仲介屋というのも案外雑なもんだなという気持ちになりました。

あと管理費・修繕積立金の将来の計画(当然年度が上がるごとに高くなる、大雑把に言って5年おきに値上がりで、30年で2倍に上昇すると見積もればだいたいOK)ですとか、固定資産税の額ですとか(これは実際に買うまで見積もりもなかなかできない、年間20万円ぐらいすることもある)、家が広くなるので水道光熱費が上がるとか、そういう諸費用は契約直前までなかなか教えてくれないので注意した方がいいです。大体不動産屋も銀行もローンと最初の管理費・修繕積立金ぐらいまでしか計算に入れずに大丈夫ですよとか言って勧めてくるので目に唾を付けて聞いてください。私の場合はお願いした不動産屋さんが知り合いのツテで、大変親切に説明していただいたお陰で難を逃れました。

買うと銀行が身近になる

家を買わない限り銀行なんてただの財布の延長程度の扱いでしかない、という感覚だと思うのですが(特に私と同年代以下の方は)、家を買うとなると銀行が本格的にお客さんというかパートナーというか商売相手になるというか・・・とにかく全く別の相手になります。銀行の担当の人とは仲良くしましょう。
それから自分の口座から頭金として3桁万円の現金札束を引き出したり、4桁万円の融資が飛び込んできたりするのが目の前で見られてちょっと社長にでもになった気持ちが味わえます。でもできればあんまり味わいたくないです(´・_・`)

買うと強制的に勉強せざるを得ない状態になる

やれ保険があるだのいざとなれば売ればいいだの言われますが、借金は借金です。返せなければ死ぬしかありません。今は金利も安いですが将来はわかりませんし、何より管理費・修繕積立金・自宅設備の更新など、将来必要になるお金は増える一方で減ることは絶対にないと悲観的に考えたほうがよいぐらいです。そして我々の給料はほっといても絶対に上がりません。退職金も年金もありません。

よく家を買うと保守的になるだの守りに入るだのというネガティブな考えを持ちそうになりますが、そんなことはありません。むしろこの激動の時代において、守りに入ったら即座に借金が返せなくなって死にます。死にたくなければ勉強し続け変化し続け攻め続けるしかありません。最大の防御は攻撃です。

そういった理由で最近はゲームをする時間もめっきり減って、代わりに株式投資だの投資信託だのの勉強をしてみたりとか、経済のニュースを見て将来の住宅ローンの金利がどうなるか調べてみたりだとか、仕事もiOSアプリばっかりいじってないでDockerだのansibleだのに手を染めてみたりだとか、筋トレする時間を毎日取って体調を維持してみたりだとか、そういうおっさんっぽい規則正しい生活を強制的に余儀なくされております。

家を買うまではそれまでの努力の成果に甘えてダラダラ過ごせてしまっていたので、家を買って強制的に借金を持って自分を追い込んだのは大正解だったと思っています。

買うと視野が広くなる

生活が強制的に変わるので当然といえば当然なのですが、その他家が広くなるので今まで置けなかった家具が置けるようになったり、筋トレ器具を置けるようになったり、最新のIoTっぽいアイテムを買って試してみたり、カーシェアリングサービスを使ってみたりと、試せるものの範囲が広がります。これは今まで生まれてきてプログラマーしかやったことがない私には大変刺激的です。特にルンバや食洗機には本当に感動していて、私が作ってきたiPhoneのアプリなんてこのルンバの1/100も人の役に立たないと反省することしきりです。

近所付き合いの話

よくタワーマンションを買うと上下格差が〜とか近所付き合いが〜とか言われますが、今私が住んでいるところでは特に上下格差が〜みたいなものは一切見られません。その代わりと言っては何ですが管理組合の人が良くも悪くも恐ろしく有能で厳しい人で、とにかく「マンションの資産価値を守る」という点において凄まじいです。引っ越しの日に私が使った業者の養生がショボかったのを見つけて廊下が割れたらどうするつもりだとものすごい勢いで業者の人に怒鳴ってました。後で菓子折り持って謝りに行きました(´・_・`)

逆に防災訓練を定期的に開催したり、子供向けのハロウィンパーティを開催したり、設備に不備があったらゼネコン建設会社や販売会社のアフターサービス担当に殴り込みに行って無償修理させるなどの活躍をしているようで、敵に回したら怖いけど味方にしたら頼りになるなぁと思って見てます。

近所付き合いに関してはやはり多少はあって、ちゃんと出会った人には挨拶して、お子さんには愛嬌よくして、お隣さんには菓子折り持ってよろしくお願いしますと挨拶に行って、ぐらいは当然必要になります。ですが慣れればなかなか楽しいものです\(^o^)/

2. 婚活をしました

30過ぎたのでいっちょ結婚ぐらいした方がいいだろと思い、ツヴァイというところに申し込んで婚活というやつをしてみましたのでご報告いたします。興味のある方は参考にしていただければと思います。

金の話

大体1年間で30万円払えばOKです。そうすると年間72人だか48人は紹介してもらえることがシステム上保証されます。私はと言うと大体300人弱ぐらい紹介を受けることができました。
なお2年目以降はまた30万円が必要になりますので、短期決戦をおすすめします。なお後述しますがどっちにしろ2年以降続けることはあまりないと思います。

ツヴァイの話

個人的にイオンが好きなのでツヴァイにしたのですが、どうやら婚活業界的には以下のようなヒエラルキーが構成されているようです。

無料アプリ
↓
Omiai, Match, ゼクシィなどの有料アプリ(1万円〜)
↓
楽天オーネット(15万円〜)
↓
ツヴァイ(30万円〜)
↓
パートナーエージェント(40万円〜)

大変身も蓋もない暴言を申しますと、上のものほど婚活とは名ばかりの出会い系アプリで、下の方になるほど今度はアラフォーの行き遅れが滞留する阿鼻叫喚地獄となっております。このことは各社の資料を取り寄せてみて平均会員年齢などを調査すれば分かるかと思います。ツヴァイはだいたい35~40歳、パートナーエージェントになると40〜50歳がボリュームゾーンとなっていました。より上位のサービスで駄目だった人が下に流れてくるという構造があるのかもしれません。

大変な暴言を申し上げてしまいましたが、やはり高い額を払うだけあって、下のサービスになればなるほど入会審査も厳格で(市町村が発行する独身証明書や2年分の源泉徴収票、大学卒業証書を提出する必要があります)、きちんとした担当の方がついてくださってアドバイスを受けたり、相手の女性の方も本気度が高いです。実際に1年間やってみてツヴァイは本当に大満足でしたのでおすすめしておきます。

婚活の話

皆さんおそらく「本当に出会えるのか?」とか「居たとしてもアラフォーの嫁ぎ遅れとサクラばかりなのでは?」とか「自分の趣味に合う人なんているわけがない」とか色々不安があるかと思いますが、断言します。そんなことは一切ありません。普通に魅力的な方ばっかりです。

私のような海外のPCゲームばっかりやってて普通の女の子の話題なんぞ何一つわからないおっさんですら、1年間で300人近く紹介してもらえまして、1/5以上の方には普通にお付き合いの連絡を申し込み、連絡先を交換して実際にお会いしたのが1/10程度で、最終的に趣味がバッチリ合う理想的な女性の方と付き合う事ができました。私自身ビックリです。年間30万円出せて本気で結婚したい方は即座に試す価値があると断言します。

あとはもう一つ気になる、どういう男が人気があるか、ですが、周りの様子を見てみたところ、汚くなくて臭くなくて笑顔が気持ち悪くなければ見た目に関してはどんな人でも全く何の心配もありません。ただし汚いのと臭いのと笑顔が気持ち悪いのだけは即座にアウトで門前払いだったのでそこだけは徹底してください。あとやっぱり身長が高くて体格が良くて声が低い人のほうが(誤差の範疇程度ですが)人気があった気がします。

職業はやはり医者と公務員から順番に売り切れます。付き合ってた彼女もおっしゃってましたが、女性は驚くほど現実を見ます。ただ当たり前ですが医者と公務員じゃないと駄目ということは一切ないのでご安心ください。

むしろそんなことより大事なのは相手を思いやる気持ちをいついかなる瞬間も忘れないことだなぁと思う次第です。

結果の話

そして皆さん気になる結果の方はですが、四ヶ月ほど付き合った彼女に私の不徳のなすところから見事にフラれまして、私が伴侶を持つに値しない人徳のない男であるということが完全に証明された形となりました(´・_・`)
これに懲りて来年以降は変な欲を持たずに良いカルマを積んでいきたいと思います(´・_・`)

3. 焼肉をおごりました





シャトーブリアン、大変美味しゅうございました。

以上、よろしくお願いします。
明日の担当は「お前、誰よ」で一世を風靡したイアン・ルイスさんです。

2016年11月17日木曜日

UITouchGestureRecognizer をやめて UILongPressGestureRecognizer や UIButton を使ってみる

適当なUIViewにUITouchGestureRecognizerを貼ってタッチアクション可能にするという実装を行うことがありますが、UITouchGestureRecognizerはUIButtonと違ってタッチして離すタイミングではなくタッチした瞬間に反応してしまうためユーザビリティ的に望ましくない場合が結構あります。

そんなときはUILongPressGestureRecognizerを代わりに使ってみましょうと言う話です。
http://stackoverflow.com/questions/12830547/how-to-implement-touch-up-inside-in-touchesbegan-touchesended

UILongPressGestureRecognizerというと、長押しして何かコンテキストメニューを表示する際に使うイメージが強いものですが、minimumPressDurationを0.01など十分に短く取ると、事実上タップとほとんど変わらないユーザビリティを得ることができます。さらにUITouchGestureRecognizerとは異なりタッチを認識した後に離すまでの間のイベントをUILongPressGestureRecognizer.stateプロパティ経由で監視することができます。その為例えば
  • タッチされている間は見た目を変える
  • タッチを話したときにアクションを実行する
といった味付けが簡単にできます。

しかしもっと簡単に透明なUIButtonを作って目的のUIViewの上に重ね、そちらにタッチをハンドリングさせたほうがより綺麗で簡単にボタンらしい挙動を再現できたので別にUILongPressGestureRecognizerを使う必要はなかったかもしれません(´・_・`) まぁこういう使い方もあるんだよという参考になれば幸いです。

ビルドが遅いのをどうにかこうにかやりくりする方法

すでに皆様痛感されていると思いますが、Swiftはビルドがとんでもなく遅いです。正確に言うと、Swiftのビルドが遅いのに加え、clang moduleのビルドが遅いため、frameworkの数が増えてくるとビルドにかかる時間がどんどん破滅的なことになってきます。

Swift & dynamic framework導入前はアーカイブ込みで10分以下だったビルド時間が、現在は20分を超えてしまっており、更に今後もSwiftコードの増加ととframeworkの増加に従ってビルド時間が伸びることが予想されます。そこでなんとかしてこの時間を短縮しようと思って調べてみました。

そもそもビルド時間が伸びる原因


  • Swiftのビルドが遅い、特に型推論が遅い
  • frameworkのビルドが遅い
  • Xcode上でcleanを実行するとプロジェクト内でビルドしているのframeworkが全てビルドし直しになり分割ビルドの恩恵が得られない

それぞれ詳しく見ていきます。

Swiftのビルドが遅い、特に型推論が遅い

以下の記事が大変参考になります。
https://thatthinginswift.com/debug-long-compile-times-swift/
Swift 3.0になって随分と高速化したため、型推論のせいで異常に時間がかかるという自体は減りましたが、それでもObjective-Cのコードと比べると10倍以上時間がかかることが多々あります。型を明示すれば高速化に寄与できますが、そうするとSwiftのせっかくの旨味が減るため悩ましいところです。

frameworkのビルドが遅い

dynamic framework = clang moduleのビルドはコードのコンパイル以上の作業を多分に含むため、分割すれば分割するほどそのオーバーヘッドが増えて無駄に時間がかかることになります。

Xcode上でcleanを実行するとプロジェクト内でビルドしているのframeworkが全てビルドし直しになり分割ビルドの恩恵が得られない

個人的に最悪なのがこれだと思います・・・せめて特定のコードに対してのみcleanできれば良いのですが、Xcodeで各種トラブルを避けるためにはcleanは必須、しかしながらcleanを実行すると全てのframeworkがビルドし直しとなって分割ビルドの恩恵が得られません。

特にCocoaPodsを使っていると全てのpod管理下のframeworkが再ビルドとなるため大変効率が悪いです。

これらを踏まえて対処法を考えてみました。と言っても大したことは出来ないのですが、

  • 定期的にビルドタイムをチェックする環境を用意する
  • CocoaPodsをやめてcarthageを使用する
  • microframeworkをやめる、どうしてもmicroframeworkを行うのであればcarthageと併用する

ビルドタイムのチェック方法は https://thatthinginswift.com/debug-long-compile-times-swift/ に記載がありますが、Other Swift Flags-Xfrontend -debug-time-function-bodiesを追加してビルドし、ビルドレポートを見ればOKです。結果はpbpaste | egrep '\.[0-9]ms' | sort -t "." -k 1 -n | tail -10などで整形すると見やすくなります。100msを超えている関数があれば手を打つ必要があるかもしれません。

CocoaPodsですが、手元で全てのframeworkをビルドしようとするためcleanした際の無駄が多いです。carthageを使えば最初にビルドを一回行って後はそれを参照して使いまわすだけ、という風にできます。ただしcarthageは最初のビルドがやたら長く、CocoaPodsを使った場合より5倍以上遅い?と言う問題があるのでその点は注意が必要です。

microframeworkを辞める論についてはおそらくいちばん賛否両論議論があるところかと思いますが、少なくとも殆どの場合、開発中はコードを使いまわす回数と時間よりXcodeをcleanしてビルドし直す回数と時間のほうが支配的であると信じています。Xcodeがちゃんとしてさえいればベストプラクティスに従ったほうが良いのでしょうが、そのようなことは伝統的にないので、ベストプラクティスにこだわらずビルドを高速化するために一つのframeworkにまとめるのも悪くはないのではと思っています。
ただしcarthageと併用できるのであれば、一度ビルドしたmicroframeworkを使いまわすメリットが享受できるので良いかもしれません。その場合、microframework側はコードベースがある程度安定している必要があります。さもなければ何度も何度もcarthage updateを走らせ直して結局時間がかかることになります。

結論

いろいろ考えてみましたが、頑張ってビルド高速化するより、新しいビルドマシンを増設したほうが結果的に良いかと思います\(^o^)/

2016/12/01 追記

Qiitaにより詳細で素晴らしいまとめがあったのでそっちを見ておいたほうが良い気がします(´・_・`)

全体的に見て型キャストとかワンライナー(とそれを誘発する演算子等)による途中の型推論が劇的に遅い原因のようですね。まぁ来年ぐらいまでにはclangが賢くなって直ってるのではないでしょうか・・・多分・・・

2016年11月14日月曜日

UNNotificationAttachment.init(identifier: String, url: URL, options: [AnyHashable : Any]? = nil)に拡張子のないURLを渡す際の注意

iOS 10で導入されたUserNotifications.frameworkは大変便利ですが、落とし穴が早速幾つか見つかっておりますのでご紹介いたします。
参考: iOS 10で画像つきのNotificationを配信する - Qiita

表題にありますUNNotificationAttachment.init(identifier: String, url: URL, options: [AnyHashable : Any]? = nil)ですが、第二引数のurlに画像や動画などのメディアのURLを渡してUNNotificationContentに付与すると言う使い方をするのが一般的かと思います。

このときどうやらUserNotifications.frameworkはurlのpathExtension、要するに拡張子の情報を利用してメディアの種類を判別しているようで、以下のような状況が発生すると実機でのみUNNotificationAttachment.initの実行が失敗してnilが返却されます。

  • 第二引数のurlに拡張子が付与されておらず、かつoptionsに[UNNotificationAttachmentOptionsTypeHintKey: "<当該URLのメディアの適切なMIME Typeを表す文字列>"]が指定されていない場合。
  • または間違った拡張子やMIME Typeが指定されている場合。

なおシミュレータでは問題ありません。いきなり実機に持っていって困るということが有るかと思いますので十分ご注意ください。

対処法は2つあります。

  1. URLに適切な拡張子を付与する
  2. optionsに[UNNotificationAttachmentOptionsTypeHintKey: "<当該URLのメディアの適切なMIME Typeを表す文字列>"]を付与する

何れにせよURLが指し示すメディアの種類が正確にわかっていないと問題になるため、その点は注意が必要です。

2016年10月4日火曜日

Q. ATS を Debug ビルドでだけ無効にしたいのですが...

A. こちらの内容に従えば一発です。

要するにBuild Phaseにビルドスクリプトを追加してそこでPlistBuddyを使って値を書き換えましょうと言う作戦です。

もうちょっとマシな解説

普段、Info.plistの設定内容をConfiguration毎に書き換えたい場合は、たいていよくやるのがxcconfigファイルを以下のように用意して、
APP_BUNDLE_NAME = MyApp_Dev
でもってInfo.plistに対して
Bundle Display Name = ${APP_BUNDLE_NAME}
こんな風に書いておけばビルド時に自動的にXcodeが環境変数による置換処理を行ってくれる、というのを使うのですが、まいったことにATSの設定を司るNSAllowArbitraryLoadsはString値ではなくBool値でして、このInfo.plistに対するXcodeの環境変数置換処理はString値(と、確かNumber値)にしか使えないというオチがあります。仕方がないので最初に説明した方法が最善になるかと思います。Info.plistファイルをConfiguration毎に用意する方法もありますが、大概そっちのほうが設定のメンテナンスが面倒になるのでオススメしません。

2016年10月3日月曜日

ATS の AVFoundationに対する 例外条項の注意点

2016/10/03段階でのATSを有効にする際の覚書です。基本的には全てTLS 1.2以上をサポートするhttpsにしてしまえばOKですが、例外条項としてAVFoundationのStreamについてはhttpでもよいと例外条項が定められています。

https://developer.apple.com/videos/play/wwdc2016/706/?time=324

これについては設定不要で自動的に適用されるようにWWDCのビデオ上では見えますが、実は落とし穴があり、この例外条項はiOS 10以降でのみしか適用されません。iOS 9については実はAVFoundationのStreamについてATSが完全に適用されているようで、httpの動画をStreamingしようとしても失敗してしまうので注意が必要です。

2016/10/03 16:45 追記
こちらXcode 7.3.1でビルドしたバイナリにて調査した内容ですので、SDKのバージョンが異なるXcode 8.0以降でビルドしたバイナリであればiOS 9.x系でもAVFoundationのStreamについてATSの例外条項が適用されてhttpで通信できるようになるかもしれません。ただ紹介した参照元のWWDCのビデオを見ても分かる通り、基本は例外を考えず全てhttps化するのが良いとされているため、ビデオストリームについても可能であれば全てhttps化するほうがトラブルがないかと思います。

2016年9月11日日曜日

Parse.com が潰れたので新しい mBaaS を探す旅に出た

定番のmBaaSとして人気だったParse.comが終わってしまうことが確定してしまった2016/09/11現在、次はどのようなmBaaSを選ぶのが良いのか調べてみました。なおどのプロダクトも全然試せていないので実戦での詳細な評価についてはできかねます。むしろこれを読んだ皆さんに果敢にトライしていただきたい!\(^o^)/

Niftyクラウド mobile backend


http://mb.cloud.nifty.com

  • 国内だとここ
  • ちょっと前にひとりぼっち惑星がここ使ってるといって有名になった
  • 正直機能的にはダメだと思ってる
    • その話題になったブログ記事の内容が、データストアにトランザクションに相当する処理を新機能として導入しました、とかDBキーによる高速ルックアップを実装しました、とかそういう次元の、あまりにも最初から存在して当然と思われる機能を新規実装として誇っているような内容だったため
    • 逆に言えば今後もこの調子で継続的に改善してくれるかも
  • Niftyが社命賭けてるっぽいしそう簡単には潰さないと信じてる

Google Firebase


https://firebase.google.com

  • なんといってもGoogle様ブランドがある
  • Analyticsが非常に素晴らしい、GAをリプレイスして、Analyticsのためだけに導入する価値がある
  • 一方でiOS/Android/Webプラットフォーム全てで同一の概念を利用できるように、各プラットフォーム独自の箇所をラップして激しく潰しているように見える
    • 特にFCMと呼ばれるPush通知に相当する箇所についてはAPNSが元の影も形も見えないぐらい激しくラップされていて操作できないため、例えば今の時期だとiOS 10向けのUserNotifications.frameworkに対応させるのが実質不可能とかそういうデメリットがある
    • iOS側が割を食いそうな不安はある
    • とはいえ調べてみたところiOS 9からのUniversal LinkはApple仕様に従ってきちんと対応するようになっていて、Firebase側は全く無視する気はなく、対応が遅れるのを許容できるのであれば大丈夫そう
  • Googleだし気合入れてるみたいだしそう簡単には潰れない・・・はず・・・
    • とはいえ最近のGoogleは不採算プロダクトを平然と潰すので油断ならない

backendless


https://backendless.com

  • パッと見一番Parse.comっぽい
  • トップページからして「Migrating from Parse? Welcome to Backendless!」だし
  • 一番Parseっぽくて下手にラップするようなことをしておらず、かつ必要な物は全部あるので最も個人的には好感
    • Firebaseみたいに激しくラップされすぎる構造は、例えるならRuby on RailsやPython Djangoのような感覚があってどうも個人的には好きになれない
  • ただしParseの二の舞いのように潰れる可能性もまた否定出来ない


まとめ

どこも潰れるリスクがワンチャンありそうですね(´・_・`)
ご利用はご計画的に\(^o^)/