困った時に iOS 開発のドキュメントやサンプルコードを探す方法

iOS アプリの開発をしていて行き詰まると Google 検索することがよくある。というかほぼ毎日やっている。検索結果として Stack Overflow や Qiita, 個人のブログ記事を見つけて、困っていた問題が解決する場合がある。解決したい問題がフレームワークやライブラリの仕組み上必要なバッドノウハウだったりすればそれで構わない。しかし特定の API について体系だって書かれたドキュメントを読んで知識を得たい場合、正しい使い方を知りたい場合、知りたかった内容が必ずしも得られるとは限らない。その場合、適当にググって見つけた記事を読むよりも効果的な方法は以下の 2 つになるような気がしている。

  • 公式のドキュメントを確認する
  • 実際に動くコードを参考にする

公式ドキュメント Apple Developer

Apple Developer

基本的に公式の情報は全てここにある。ただ自分としては、初心者にはいまいち知りたい情報を探しにくいし取っつきづらいと感じている。

そこで Apple のエンジニア直伝の開発ドキュメント検索方法。昨年 WWDC のラボで

「 developer.apple.com って初心者にはいまいち知りたい情報を探しにくくないですか?例えばあなたはどうやってドキュメントを調べていますか?」

Apple のエンジニアに質問してみた。すると、そのエンジニアはそれは課題だと感じていて、 Google のサイト内検索機能を使っていると教えてもらった。

Google のサイト内検索

Google で検索したい内容を入力する時に、検索バーに site:https://developer.apple.com と入れることで、サイト内検索をすることができる。 例えば URLSession について調べたければこんなかんじ。

f:id:enmtknt:20190221182742p:plain

Xcode のドキュメント

同じように Xcode でドキュメントを調べることもできる。(Xcode 10.1)

Xcode を起動 -> Help -> Developer Documentation

f:id:enmtknt:20190221183629p:plain

実際に動くサンプルコード

実際に動くコードの例を探したいことは良くある。その場合に考えられるのが以下の方法。

  • GitHub でコードを検索する
  • Apple Developer のサンプルコードを読む

GitHub のコード検索

GitHub には世界中のエンジニアが書いたライブラリやフレームワークのコード、定番ライブラリを組み込んだアプリのコードがたくさん公開されている。これらは未経験の開発言語やフレームワーク、新しいライブラリを使う場合とても参考になる。検索ツールを使えば、言語や公開時期など細かい条件を指定してコードを検索することができる。

GitHub · Where software is built

f:id:enmtknt:20190222183023p:plain

Apple Developer のサンプルコード

Apple Developer にも動くプロジェクトとしてサンプルコードが公開されている。ぱっと見探しづらいが以下の方法で調べることができる。

Google サイト内検索を利用して検索

前述と同じ方法。

site:developer.apple.com Sample Code と入力する。

f:id:enmtknt:20190221183931p:plain

Documentation Archive の Sample Code

以下の Documentation Archive の Sample Code にも色々まとめられている。

Documentation Archive

f:id:enmtknt:20190221184214p:plain

所感

忙しいと Google 検索して済ませがちだけど、やはりオフィシャルのドキュメントにはフレームワークの正しい使い方が書いてあるし、実コードを手元で動かしたり、様々な使い方を目にすることで自分のコードに活かせる新しい発見がたくさんあるように思う。

fastlane deliver で Multiple App Store Connect Teams found; unable to choose, terminal not interactive! が出た時の解決方法

CircleCI 上で実行した $ fastlane deliver

Multiple App Store Connect Teams found; unable to choose, terminal not interactive!

というエラーが出た。

先に結論を述べると、職場で利用している Apple Developer Program のアカウントが複数のチームに紐付いていたのが原因だった。 最近 Enterprise アカウントを作成したことの副作用で発生した出来事だった。

解決方法としては、deliver のパラメータに Team ID を明示的に渡してやる。Deliverfile に書いてやるのが簡潔で良い。 ちなみに自分のプロジェクトで使っている Deliverfile は以下の通り。内容は一部改変している。

app_identifier “jp.foo.bar"
username “buz@example.com"
team_id “xxxxxxxxxxx"
force false
skip_screenshots true
skip_metadata true
skip_binary_upload false
automatic_release false

ちなみに1点気をつけることがあり、この時 Team ID として入力するのは、 Developer Program で確認できる 10 桁の Team ID ではなく、 Spaceship で取得できる数値。 fastlane が実行できる環境であれば、irb も Spaceship を使えると思う。以下のように取得する。

$ irb
irb> require "spaceship"
irb> Spaceship::Tunes.login("iTunesConnect_username", "iTunesConnect_password")
irb> Spaceship::Tunes.select_team

環境

  • Ruby 2.3.1
  • fastlane 2.113.0

参考

Web API に依存するモジュールのテストに使う extension

環境

Xcode 10.1, Swift 4.1

Web API に依存するモジュールのテスト

iOS アプリ開発において、 Web API にリクエストするモジュールのユニットテストを書くことは良くあると思う。その場合 Web API にそのままアクセスするテストを書くと、返す値によってテスト結果が変わる脆いテストになってしまう。そのため Web API の戻り値をスタブして、 実際には HTTP リクエストを行なわないというのが基本になる。

HTTP リクエストをインターセプトして、任意の値を返すために使うライブラリは kylef/Mockingjay, AliSoftware/OHHTTPStubs 辺りが定番で、僕は Mockingjay を好んで使っている。Mockingjay のインストール方法は GitHub の README.md を参考にしてほしい。また、Web API の戻り値を json に肩代わりさせるが、その方法については以前書いた Qiita の記事に詳しい。

iOSプロジェクトのテストバンドルに存在するファイルを取得する - Qiita

簡便のための extension

以下の extension を用意することで、呼び元で簡潔にスタブすることができる。

gist.github.com

Quick を使った場合のテストケースの例

呼び元のコードはこのように書く。XCTest を使う場合も呼び方は変わらないが、非同期のテストを書く場合少し工夫が必要になる。

gist.github.com

所感

ユニットテストに限らず、本質的にやりたいことを実現するためにはどうしても煩雑なコードが必要になる場合がある。コードの保守性を高く保つ為には、複雑性を隠蔽して明解なインターフェースに落とし込み、呼び元のレイヤを簡潔に保つことが必要不可欠になる。

iOS アプリのバージョンをインクリメントするためのスクリプト

iOS アプリをストアにリリースする時にはバージョン番号を上げる作業が必ず発生する。その際に Info.plist を手作業で更新するのは手間だしミスが発生する余地があるので、 Pythonスクリプトを使って自動化している。以下のスクリプトを アプリのプロジェクト直下に配置し、実行する。 Python 2.7 でも 3 系でも動作する。

This script bumps iOS app version numbers. (Python ...

調べていたら Fastlane にも increment_version_number というコマンドがあったので、CI に導入する場合はこちらを使うのも良いかもしれない。バージョンのインクリメントに限らずアプリ開発で面倒な作業はなるべく自動化していきたい。

アメリカで契約したAT&TのSIMを解約するために国際電話をかけた話

tl;dr

アメリカで契約した AT&T の SIM を解約するために、AT&Tのカスタマーサポートに国際電話をかけた。自身のアカウントを認証するために、氏名、電話番号、 SIM カードの No. が必要だった。

顚末

昨年 WWDC で渡米した際に現地で AT&T の SIM を契約した。しかし解除したと思われていた自動引き落としがキャンセルされておらず、毎月 4,500 円程度の引き落としが半年間かかっていた・・・。完全に自業自得で気づかないのもどうかしているが、そんなわけで慌ててキャンセル方法を調べた。Web で AT&T のアカウントを管理する仕組みがあるのだが、店舗で行った初回パスワードの設定に失敗しており、ログインすることができない。パスワードリセットの仕組みはあるものの、その方法は SIM に紐づく電話番号にショートメッセージで新しいパスワードを送信するというもの。つまりアメリカ国内でないとショートメッセージを受け取れない。詰んだ。困り果ててどうにか解約する方法を調べていたが、チャットを使ったオンラインサポートがあること、カスタマーサポートに電話をすれば解約できるはずということを Quora で教えてもらい、それぞれ試してみることにした。

チャット

国際電話を掛けるのはお金がかかるし英語でのやり取りがしんどそうだったので最初はチャットで問い合わせをすることにした。日本とアメリカの時差を調べて出勤前の時間にチャレンジした。ウインドウを開くとすぐに会話が始まり、氏名と電話番号からこちらのアカウントをチェックしてくれた。先に質問文を作っておいたこともあり、やりとりはスムーズだった。

こういうやつ http://i.imgur.com/FLkFD7v.png

しかし、プリペイドSIMについてはチャットサポートの対象ではないと言われてしまい、案内してもらった電話で直接話をすることになった。

カスタマーサービスとの電話

教えてもらった番号に電話をかけるとすぐに繋がった。日本の銀行などの窓口とほとんど変わらない。2, 3 分無機質な宣伝メッセージを聞いた後にオペレータと電話が繋がった。チャットの時と同じ質問を投げかけて自分の状況を伝えることはできたが、当該番号が自身のアカウントだと証明するのに四苦八苦した。対応は親切でこちらの拙い英語に根気強く付き合ってくれた。最終的に "successfully caceled" という言葉を聞いた時には安堵した。

終わりに

今回初めて電話越しに英語で会話したが、自分は電話口の英語が全然理解できないということが分かった。相手の表情や身振り手振りがないこと、相手がこちらが理解できているかを分からないので要件を繰り返し述べることしかできないことが原因なのかなと思う。こちらが言ったことが相手にちゃんと伝わっているのかどうかも分かりづらかった。 これを機に時間を作って英会話の練習もしたいと感じた。だいぶ高い授業料を払ったが良い経験になった。

iOS で opencv_contrib のモジュールを使う

iOSopencv_contrib のモジュールを使う方法を調べた。 OpenCV 本体を使いたければ Cocoapods でビルドするだけだが、opencv_contrib に含まれている拡張モジュールを使う場合、opencv2.framework をゼロからビルドして、それをプロジェクトに追加する必要があった。

環境

手順

ソースコードのダウンロード

以下のURLからソースコードをダウンロードして、任意の作業ディレクトリに解凍する

ディレクトリ構成は以下のようになる

my_working_directory
├── opencv-3.4.5
│   ├── 3rdparty
│   ├── CMakeLists.txt
│   ├── CONTRIBUTING.md
│   ├── LICENSE
│   ├── README.md
│   ├── apps
│   ├── cmake
│   ├── data
│   ├── doc
│   ├── include
│   ├── modules
│   ├── platforms
│   └── samples
├── opencv-3.4.5.zip
├── opencv_contrib-3.4.5
│   ├── CONTRIBUTING.md
│   ├── LICENSE
│   ├── README.md
│   ├── doc
│   ├── modules
│   └── samples
└── opencv_contrib-3.4.5.zip

ビルド

作業ディレクトリで以下のコマンドを実行

$ python ./opencv-3.4.5/platforms/ios/build_framework.py ios --contrib ./opencv_contrib-3.4.5

Python のバージョンに注意

Mac にプリインストールされている Python 2.7 を使っていれば特に問題ないが、もし Python 3 を使用している場合ビルドが失敗する。pyenv を使うなどして python コマンドが Python 2.7 を参照するように設定する。

CMake のバージョンに注意

Python 2.7 で再ビルドしたら以下のエラーが出てビルドが失敗した。

error: Build input file cannot be found: '/Users/foo/Documents/my_working_directory/ios/build/build-armv7-iphoneos/modules/world/opencl_kernels_video.cpp'

ググってみると CMake のバージョンが古いことに起因するビルドエラーの issue が立っていた。

Unable to build framework for iOS · Issue #12646 · opencv/opencv

以下のコマンドで CMake のバージョンを確認できる。

$ cmake --version
cmake version 3.11.3

これが原因のようなので Homebrew で CMake のをアップデートする。

$ brew upgrade cmake
$ cmake --version
cmake version 3.13.2

ビルド成功

再ビルドを行う。

各デバイスのCPUアーキテクチャ向けにそれぞれバイナリをビルドするので、それなりの時間がかかる。

ビルドが成功すると作業ディレクトリ直下に ios/opencv2.framework が出来る。

opencv2.framework/Headers を参照すると、 opencv_contrib のモジュールも含まれていることが分かる。あとはビルドした opencv2.framework をプロジェクトにコピーすれば、C++ のファイルから opencv_contrib のモジュールを参照できる。

framework を iOS のプロジェクトに追加する方法と C++ のコードを Swift のプロジェクトから参照する方法は他に沢山の記事があるので割愛する。

所感

Python 3 が大多数となった現在でも OpenCV のビルドツールは Python 2.7 のままだった。 以前触れた Swift コンパイラのビルドツールも Python 2.7 だった。普段使いの Python が 3 系でも、歴史あるツールを Python でビルドする機会がある場合は pyenv や virtualenv でクリーンな作業環境を維持すると良さそう。

2018年のふりかえり

年が明けてそろそろ一週間経とうとしているが年末書けなかったのでざっとふりかえる。

アウトプット

ブログ

大小合わせて 15 個記事を書いた。考えたことを文章にすることで抽象化する練習やアウトプットへの心理的な障壁を下げたい気持ちがあり、少しは目的を果たせた。 Qiita にも申し訳程度に投稿した。

OSS

try! Swift San Jose で Swift コンパイラにコントリビュート出来たのは嬉しかった。今年前半は言語処理系を勉強していて GNU 開発ツール を読んだり、Go言語でつくるインタプリタ を写経したり、言語処理系と以前より仲良くなれた1年だった。

WWDC

今年初めて参加した。とても良かった。沢山刺激を受けたし、現地で多くのエンジニアと交流できたのも良かった。WWDC をきっかけにあらためて英語の必要性を感じて、今年後半は TOEIC の勉強をした。

仕事

iOS エンジニアとしてアプリ全般を広く見ていた。CI/CD, ユニットテスト周りは得意分野と認識していて、ザクザクと環境を整えた。ただ事業貢献という意味で価値創出できているのかと悩むこともあり、来年は iOS に閉じずに新しい機会を作りたいと思っている。

自作キーボード

夏に一目惚れして購入した Mint60 を年末に組み立てた。出来上がったものを使うのも楽しいが、組み立てる工程自体がとても楽しく、これは新しい趣味になるのではないかという予感すらしている。来年は Iris Keyboard を作りたいと密かに思っている。

とりとめなくなったがこんなかんじで。