“私の WatchKit での大きな失敗”

Apple Watch の登場を祝い、何人かの友達にこの Apple の新しいプラットフォームから学んだことについて共有してもらうようお願いしました!

パート2はこちらです。


Natasha Murashev

iOS Engineer at Capital One and blogger at Natasha The Robot

私の一番の失敗は Watch からメッセージを送信するときに iOS 側のアプリが起動すると思っていたことです。 WatchKit には iOS 側にメッセージを素早く送るための API があります。それは、バックグランドプロセスで起動するトリガーとなります。バックグランドプロセスを起動させるためには以下の WKInterfaceController のクラスメソッドを呼び出す必要があります。

// WKInterfaceController
class func openParentApplication(userInfo: [NSObject: AnyObject],
                                    reply: (([NSObject: AnyObject]!, NSError!) -> Void)?) -> Bool

// launches containing iOS application on the phone
// userInfo must be non-nil

しかし、ユーザーの iOS アプリは開かないのです! WatchKit ベータ版ではシミュレータの iOS アプリが開きます。なので、こういった機能なのだとすっかり思い込んでいました。実際は iOS アプリがバックグランドで開くだけです。これは、情報を受け取り必要なタスクを実行するには十分です。

Natasha の Apple Watch に関するビデオ: Architecting Your App for the Apple Watch


Brian Gilham

Senior Mobile Developer at TWG and blogger at Five Minute WatchKit

一番の失敗は iOS シミュレータのみで開発を行っていたとき、アプリが BTLE 通信をしているのをよく忘れてしまうことです。シミュレータではレイテンシをわざとリクエストに追加することでこれを再現しようとします。しかし、実際のデバイスではレスポンスタイムは時々かなり遅い場合があります。

アプリの設計、開発しているときに以下の3つの質問を自分に問いかけると良いと思います:

  1. このビューやアクションのレスポンスタイムが遅い場合は何が起こるか?
  2. レスポンスが全て受け取れなかった場合はアプリはどのような反応になるか?
  3. これらの問題を解決するために何ができるか?

この問題の解決策は、それぞれのアプリによって違います。以下にいくつか考えられることを書いておきます:

  1. 二度以上 API を叩いたり画像を取得することはせず、できるだけキャッシュさせることを考えましょう。もしニュースフィードが15分に一度もアップデートされないのなら、アプリ起動時に毎回 API を叩きにいってもあまり意味のないことだと思います。
  2. データをユーザーが使用する前にダウンロードするようにしましょう。キャッシュとデータの保存を組み合わせた iOS アプリでバックグランドフェッチを実装するとかなり UX が違ってくると思います。
  3. ユーザーを待たせてしまう場合、ローディングアニメーションをきちんと表示させてください。ユーザーにアプリが固まったと思わせてはなりません。同じようなことで、リクエストが失敗した場合は UI を更新するかきちんと知らせる必要があります。

Good luck! 何を作るか楽しみにしています!


Conrad Kramer

Creator of Workflow

早い段階で画像を取得する問題がありました。永遠にロードし続け Watch Extension のメモリ使用量が増えクラッシュするというものでした。それからいくつか試行錯誤した結果、以下が画像を Watch に送る私の最善の Tips です。

  • スクリーンに表示させるそのままの大きさの画像を作るようにしてください。
  • JPEG か PNG に圧縮してください。
  • NSData を引数に取る -[WKInterfaceImage setImageData:] を使ってください。UIImage を使うより速く、メモリ効率が良いです。

アニメーションイメージが必要な場合は +[UIImage animatedImageWithImages:duration:] を使ってください。NSKeyedArchiver を使いエンコードし、NSData としてデータを送ってください。

* ここで気を付けることは Watch はこの duration プロパティを考慮しません。
-[WKInterfaceImage startAnimatingWithImagesInRange:duration:repeatCount:] で指定された duration になります。


James Robert

CTO at Media Predict

私の大きな失敗は、アプリのグラフィック要素を Watch で使おうとしたことです。制限がある環境に最適化されたアプローチを取るために一からデザインを考える必要があります。

画像を扱う場合とても注意しなければいけません。- 上記で Conrad も言っているように、満足できるパフォーマンスを得るために JPEG に圧縮した NSData を使用するべきです。しかし私の場合以前は CSS でするような背景色や border radius などのみ使用していました。Watch のスクリーンはかなり小さいです。テキストのスペースを確保するためにできることはやらないといけません。四角いチェックボックスをこのように長細いドットに変更しました。


Curtis Herbert

Independent Developer & Designer

私の一番の失敗はビューの更新はそれほど賢くないということです。これは Slopes を開発中に気付いきました。iOS 開発でやっていたように値が実際に変わっているのかどうかにかかわらず、スクリーンは更新したいときに更新すればいいと考えるのは簡単です。
しかし、注意してください! 全ては帯域に制限がある Bluetooth 経由で行われるということです。

Xcode のコンソールに見ていると WatchKit がビューの更新が重複している箇所を取り除こうとしているのがわかると思います。didDeactivate が呼ばれた後の View の更新は全て無視されます。Apple は Bluetooth 経由での更新を最小限に止めることに関して、非常にアグレッシブにやっています。しかし WKInterfaceControllerWKView にはこの状態をトラックし続ける機能(プロパティを取得したりするような明確な理由がある場合を除いて)はそれほど多く提供されていません。

キーとなる View の値(ラベルのテキストや画像の名前や View の hidden の値など)をトラッキングする CachingInterfaceController を継承して、全てのコントローラを作るようにしています。今のところは少し素朴なやり方ですが WatchKit ラボで半日ほど作業をした結果です。コードは GitHub をご覧ください。かなりコントローラがシンプルになり、イベント駆動のコードを MMWormhole と WFNotificationCenter に移したようにかなりの状態をトラッキングする部分を抽象化できました。

ビューの状態をトラッキングする必要があることを受け入れ、このようなコードを書くことにしたらたくさんの問題が解決しました。

Curtis の Watchkit Communication の動画と ブログ がご覧になれます。


Neil Kimmett

Developer at M&S Digital Labs

WatchKit での一番の失敗は、テキスト要素に多くの余白を含めていたことです

デスクトップやモバイル向けにデザインしているときは、スクリーンの端とテキストの間に margin を置いています。しかし WatchKit では、黒の背景を使っていると、Watch のフレームは、コンテンツに対して勝手に margin がかけられたように見えます。テキストの右側はスクリーンの端にくっついています。シミュレータではかなり奇妙なことだと思いますが、実際のデバイスでは縁が黒色なので普通です。Watch の限られたリソースの中でより多くのスペースを使えるメリットがあります。

Neil のブログもご覧ください。


Kristina Thai

iOS software engineer at Intuit

私がした一番の失敗は handleWatchKitExtensionRequestカスタムクラスのオブジェクトを Dictionary で Watch Extension に渡そうとしたことです。オブジェクトを replyInfo として渡せたのですが plist 形式にシリアライズできずに例外が発生しました。カスタムオブジェクトを渡そうとすると以下のようなエラーメッセージを受け取ります。

Error Domain=com.apple.watchkit.errors Code=2 "The UIApplicationDelegate in the iPhone App never called reply() in -[UIApplicationDelegate application:handleWatchKitExtensionRequest:reply:]" UserInfo=0x61000006f640 {NSLocalizedDescription=The UIApplicationDelegate in the iPhone App never called reply() in -[UIApplicationDelegate application:handleWatchKitExtensionRequest:reply:]}

カスタムオブジェクトの場合 plist 形式にシリアライズできないので、親の iPhone アプリの handleWatchKitExpensionRequest の中で reply() が呼べません。

iPhone アプリと Watch Extension との間でデータを共有するにはいくつか方法があります:

  1. データの受け渡しに Dictionary 型はもちろん使うことができます。Watch に表示させるためのカスタムオブジェクトが持ついくつかの String プロパティでした。なので、それらを Dictionary に入れて簡単に渡すことができました。ステータスコードや簡単なメッセージなどを渡すために(String型と他のプリミティブ型)が使えます。少し複雑なデータを渡すために Array 型や Dictionary 型で渡せます。

  2. カスタムオブジェクトの全てのプロパティを渡す必要がある場合 App Groups をセットして、必要に応じて NSUserDefaultsNSFileManager のどちらかを使えば良いです。(注意すること: NSFileManager を使って SharedContainer に読み書きする場合は、データ破損することを防ぐ必要があります)

  3. NSKeyedArchiver でカスタムオブジェクトをアーカイブし Directory の中に入れて渡します。以下のようなコードです:

iPhone 側で Dictionary を作ります。

NSMutableDictionary *reply = [NSMutableDictionary new];
MyCustomObject *myObject = <something you need to send>;
reply[@"myKey"] = [NSKeyedArchiver archivedDataWithRootObject: myObject];
NSAttributedString *myString = <some attributed string>;
reply[@"otherKey"] = [NSKeyedArchiver archivedDataWithRootObject: myString];

Watch 側で元に戻します。

NSData *objectData = replyInfo[@"myKey"];
MyCustomObject *myObject = [NSKeyedUnarchiver unarchiveObjectWithData: objectData];
NSData *stringData = replyInfo[@"otherKey"];
NSAttributedString *myString = [NSKeyedUnarchiver unarchiveObjectWithData: stringData];

Brian Montz コードを共有してくれてありがとう!

一番大事なこと: どの情報が必要なのか特定すること。そして、その情報を WatchKit Extension と iPhone アプリ間で共有する最善の方法を決めることです。

Kristina の WatchKit のチュートリアル と ツイッターは @kristinathai です。


Orta Therox

Head of mobile at Artsy & Design Dictator at CocoaPods

Apple Watchがまだ出荷されてないことを恐れないで下さい。変に聞こえますが、時にアプリは他のスクリーンでは、想像している通りに動かないときがあります。Watchアプリのテスト環境はまだ提供されていません。(Cedar を使えばできるとも聞きましたが)はっきりとした契約による設計がされていないコードがたくさん世の中にリリースされることになると���うことです。例えば、他の開発者が変更を加えたいとすれば、影響を与えるコンテキスト全てを把握する必要があります。クールで新しいものであると対照的に、私の Watch アプリはバ���が出るぐらいには大きい規模のものです。そういった理由で、必ずテストが必要という意味ではありません。

皆さんありがとうございました! 明日を楽しみにしておきましょう!

記事の更新情報を受け取る

About the content

This content has been published here with the express permission of the author.


Natasha Murashev

Natasha is secretly a robot that loves to learn about Swift and iOS development. She previously worked as a senior iOS Engineer at Capital One in San Francisco, but now she travels around, writing about her experiences with new technologies. In her free time, she works on personal projects, speaks at meetups and conferences, contributes to open source, and likes to cross things off her bucket list.

Brian Gilham

iOS developer at @TWG. I write about shipping side projects, being more productive, and doing good work. I got fired from Home Depot for building a fort, once.

Conrad Kramer

Conrad Kramer started developing for iOS after he got involved with the jailbreak scene back in 2010 with his first tweak Graviboard. Since then, he has gotten into regular iOS development and worked on various open source projects in the Cocoa community, like AFOAuth2Client and WFNotificationCenter. Conrad now spends all of his waking hours on Workflow, an automation tool for iOS, where he works on anything from the server backend to building the complex drag and drop interactions.

James Robert

Person who cares about things. On the internet: always jiaaro

Curtis Herbert

Curtis Herbert is an independent iOS app creator, writer, speaker, and Apple enthusiast. Spends his free time enjoying 🎮, 🏂, and most things 🤓, living in the suburbs of Philadelphia.

Neil Kimmet

I’m an iOS Developer, currently working at Harry’s. Before that I worked on Move Loot, Cook With M&S and Artfinder. This is my corner of the internet. Find me on other bits of the internet below.

Kristina Thai

Kristina Thai is currently an iOS software engineer at Intuit. She works on the QuickBooks Self-Employed iOS app. Kristina is an avid blogger at kristina.io and spends her time writing iOS and watchOS development tutorials and blogging about her early career experience. She started her engineering career after graduating from the University of California, San Diego with a degree in Computer Science. Fun fact: she follows more animals on Instagram than people.

Orta Therox

Orta is the lead iOS developer at Artsy, building beautiful portfolio apps for some of the biggest Art galleries in the world. Encouraged by Artsy’s awesome commitment to open source, he regularly devotes time to working on and around the CocoaPods ecosystem, building tools like CocoaDocs, maintaining the Specs repository, and pruning documentation. If the CocoaPods team had fancy titles, he’d probably be called a community manager.

4 design patterns for a RESTless mobile integration »

close