sniper, the OSX app terminator in Swift

sniper というコマンドラインツールをSwiftで作ったので、作る過程で得られた知見も交えて紹介したいと思います。

f:id:toshi0383:20151107082936p:plain

github.com

TL;DR

  • sniper は、アプリのプロセスを探して殺すことができる簡単なコマンドです。
  • bin/sniper をどこかにコピーして使ってください。
  • sniper はCIプロセスで使うとたまに便利だと思います。
  • sniperOSX以外のアプリは見つけられないし殺せません。
  • アプリのプロセスを殺すにはNSRunningApplicationを使いました。
  • コマンドラインツールにはDynamic Frameworkは組み込めないため、壮大なワークアラウンドが必要。(なので諦めましょう。)
  • サバゲーが楽しみすぎて sniper とかちょっと恥ずかしい名前つけてしまった。

背景

下記の課題がありました。

  • UIテストをCIプロセスに組み込みたいが、初回起動時にしか出ないダイアログとかがある
  • 使用するSimulatorを決めてアプリを使い回すよりは、毎回リセットして初回起動として扱いたい
  • Simulatorをリセットするには、泥臭いAppleScript を書くか、 Simulatorを削除(rm -rf ~/Library/Developer/CoreSimulator/Devices/*) するしかない模様だった
  • AppleScriptは書きたくない
  • でもSimulatorが起動している状態で上記の rm コマンドで削除すると、次回ちゃんと起動しなくなってテスト失敗する
  • Simulatorを駆逐したい

というわけで、Simulatorを殺すうまい方法はないかと調べていたわけです。

ps コマンドからの kill ${pid} のことを思い出したんですが、なんとなくOSXではご法度な気がするし。。

で、見つかりました。

NSRunningApplication

NSRunningApplication というのがあって、これに terminate() というメソッドがあります。こいつを取れれば、殺せそうです。

取得する方法はいくつかあるみたいで、

NSRunningApplication.runningApplicationsWithBundleIdentifier(bundleId)

もしくは

NSWorkspace.sharedWorkspace().runningApplications

でもこれで本当に自分以外のプロセスも取れちゃうんでしょうか。やってみましょう。

$ echo "import AppKit; NSWorkspace.sharedWorkspace().runningApplications.forEach{print(\$0)}" | xcrun swift
Welcome to Apple Swift version 2.1 (700.1.101.6 700.1.76). Type :help for assistance.
<NSRunningApplication: 0x10060aa50 (com.apple.loginwindow - 89)>
<NSRunningApplication: 0x10060aae0 (com.apple.inputmethod.Kotoeri - 271)>
<NSRunningApplication: 0x10060abe0 (com.apple.internetaccounts - 277)>
<NSRunningApplication: 0x10060ace0 (com.apple.AirPlayUIAgent - 279)>
<NSRunningApplication: 0x10060ade0 (com.apple.iChat - 296)>
<NSRunningApplication: 0x10060aee0 (com.apple.systemuiserver - 303)>
<NSRunningApplication: 0x10060afe0 (com.apple.dock - 302)>
<NSRunningApplication: 0x10060b0e0 ((null) - -1)>
<NSRunningApplication: 0x10060b1e0 (com.apple.finder - 304)>
<NSRunningApplication: 0x10060b2e0 (com.apple.sharingd - 309)>
<NSRunningApplication: 0x10060b3e0 (com.adobe.accmac.ACCFinderSync - 312)>
<NSRunningApplication: 0x10060b4e0 (com.apple.dock.extra - 315)>
<NSRunningApplication: 0x10060b5e0 (com.apple.Spotlight - 317)>
<NSRunningApplication: 0x10060b6e0 (com.apple.storeuid - 335)>
<NSRunningApplication: 0x10060b7e0 (com.apple.MailServiceAgent - 458)>
<NSRunningApplication: 0x10060b8e0 (com.apple.iTunesHelper - 486)>
<NSRunningApplication: 0x10060b9e0 (com.kensington.trackballworks.helper - 488)>
<NSRunningApplication: 0x10060bae0 (com.security.apple.Keychain-Circle-Notification - 468)>
<NSRunningApplication: 0x10060bbe0 (com.apple.TISwitcher - 487)>
<NSRunningApplication: 0x10060bce0 (com.apple.notificationcenterui - 470)>
<NSRunningApplication: 0x10060bde0 (com.fabriceleyne.hourlite - 491)>
<NSRunningApplication: 0x10060bee0 (com.linebreak.CloudAppMacOSX - 492)>
<NSRunningApplication: 0x10060bfe0 (com.apple.wifi.WiFiAgent - 481)>
<NSRunningApplication: 0x10060c0e0 (com.adobe.acc.AdobeCreativeCloud - 478)>
<NSRunningApplication: 0x10060c1e0 (com.adobe.AdobeIPCBroker - 504)>
<NSRunningApplication: 0x10060c2e0 (com.adobe.acc.AdobeDesktopService - 514)>
<NSRunningApplication: 0x10060c3e0 (com.adobe.acc.HEXHelper - 515)>
<NSRunningApplication: 0x10060c4e0 (com.adobe.accmac - 517)>
<NSRunningApplication: 0x10060c5e0 ((null) - -1)>
<NSRunningApplication: 0x10060c6e0 (com.apple.lateragent - 534)>
<NSRunningApplication: 0x10060c7e0 (com.apple.cloudphotosd - 729)>
<NSRunningApplication: 0x10060c8e0 (com.apple.EscrowSecurityAlert - 1049)>
<NSRunningApplication: 0x10060c9e0 (com.apple.nbagent - 1341)>
<NSRunningApplication: 0x10060cae0 (com.apple.Terminal - 1447)>
<NSRunningApplication: 0x10060cbe0 (com.apple.iCal - 52911)>
<NSRunningApplication: 0x10060cce0 (co.gitup.mac - 65045)>
<NSRunningApplication: 0x10060cde0 (com.apple.Safari - 16036)>
<NSRunningApplication: 0x10060cee0 (com.apple.WebKit.Networking - 16038)>
<NSRunningApplication: 0x10060cfe0 (com.tinyspeck.slackmacgap - 16258)>
<NSRunningApplication: 0x10060d0e0 (com.apple.qtkitserver - 16266)>
<NSRunningApplication: 0x10060d1e0 (com.apple.WebKit.Plugin.64 - 16272)>
<NSRunningApplication: 0x10060d2e0 (com.apple.WebKit.Databases - 84902)>
<NSRunningApplication: 0x10060d3e0 (com.apple.WebKit.WebContent - 2098)>
<NSRunningApplication: 0x10060d4e0 (com.github.atom - 5135)>
<NSRunningApplication: 0x10060d5e0 (com.github.atom.helper - 5141)>
<NSRunningApplication: 0x10060d6e0 (com.apple.coreservices.uiagent - 13010)>
<NSRunningApplication: 0x10060d7e0 (com.apple.WebKit.WebContent - 13061)>
<NSRunningApplication: 0x10060d8e0 (com.apple.WebKit.WebContent - 13066)>
<NSRunningApplication: 0x10060d9e0 (com.apple.WebKit.WebContent - 13067)>
<NSRunningApplication: 0x10060dae0 (com.apple.WebKit.WebContent - 13068)>
<NSRunningApplication: 0x10060dbe0 (com.apple.dt.Xcode - 13088)>
<NSRunningApplication: 0x10060dce0 (com.apple.iphonesimulator - 13512)>
<NSRunningApplication: 0x10060dde0 (com.apple.WebKit.WebContent - 13632)>
<NSRunningApplication: 0x10060dee0 (com.apple.WebKit.WebContent - 13633)>
<NSRunningApplication: 0x10060dfe0 (com.apple.WebKit.WebContent - 13636)>

めっちゃとれちょる。というわけでこれでいけそうです。

コマンドラインツールの作成

で、CIに組み込むのでコマンドラインツールにしたかったんです。
以前 kitasuke氏のスライド を見て試したことがあって、非常に大変だったことは覚えていたのですが、まあとりあえずやってみようということで。

で、今回は案外簡単にできました。
Xcodeのプロジェクトテンプレートも Command Line Tool です!
オプションのパース用にライブラリが必要だったのですが、たまたま選んだSwiftCLI がgit-submoduleでのインストール推奨にしてくれていたため、DynamicFrameworkのための壮大なワークアラウンドが必要なかったのです。
というかまあソースコード直接突っ込めばなんでもいけるわけです。ただ、SwiftはModuleのnamespaceがあるので、ClassPrefixをつけるとかいうObjective-Cの素晴らしい文化は、基本的にはありません。よってライブラリ同士でクラス名が競合することが多く、その場合どうするかというと。。考えたくもないですね。(自分でprefixつけて回る?いやいやいや。。)

なぜDynamicFrameworkがコマンドラインツールに直接組み込めないのかというと... まあいまはそういう仕様なんです。諦めましょう。
どうしても組み込みたい方は上記kitasukeさんのslideとか、これも参考になるかと思います。

使い方

使い方は、こんな感じになりました。README.mdから抜粋です。

# List all running apps
$ sniper target
37 apps found.
com.apple.loginwindow: 89
.
.
.

# Filter by keyword
$ sniper target firefox
1 app found.
org.mozilla.firefox: 4822

# Terminate process by bundle ID
$ ./sniper shoot -b org.mozilla.firefox
Terminating org.mozilla.firefox: 4822 ...

# Terminate process by PID
$ sniper shoot -p 4703
Terminating com.apple.iphonesimulator: 4703 ...

で、今回の目的 "Simulatorを駆逐する" を達成するには、こうすると良いと思いました。

$ sniper shoot -b com.apple.iphonesimulator  # shutdown before reset(remove) all simulators
$ rm -rf ~/Library/Developer/CoreSimulator/Devices/*

TravisやCircle、bitrise のようなCIサービスであればコンテナが毎回使い捨てだと思うので、なにも考えなくても毎回すべてのアプリが駆逐された状態かと思いますが、余っているMacにJenkins立てているケースも多々あるかと思いますので、そういった場合に使えるかと思います。

まとめ

というわけで、Swiftで簡単にコマンドラインツールを作ることができました。
簡単な処理だと他のscript言語の方が簡単にかけるケースの方がよっぽど多いと思いますが、Macアプリのプロセスをどうこうするとかの場合は、AppKitを使うのが一番手っ取り早そうだなというのが所感でした。

以上になります。

参考

Swift array map の性能測定の続き

前回の続き

前回の記事に対して@es_kumagai さんからフィードバックをいただきました。
今週忙しくて、やっと見る時間が取れました。

結論から言うと、今回の検証方法(ターミナルからswiftやswiftc を利用する)においては、標準のmapより速い実装が手に入りました。

たった1000件での比較ですが、こうなりました。前回から計測方法も多少改善しました。手抜きですみません。

map : 0.000211954116821289
map7: 0.000133037567138672

まあ1/10000 秒の差とか、もはやモバイル開発においてはどうでもいい話ですね。めちゃくちゃ大量のデータ扱うこともそう滅多にないでしょうし。

ボトルネックはやはりarrayの初期化だったようです。
コードはフィードバックでいただいたものを貼っておきますね。ありがとうございます。

gist.github.com

-O オプション

なお、-OをつけるとDouble値の出力がおかしくなりました。
どうして。。?

$ xcrun -sdk macosx swiftc -O  map.swift
$ ./map 
=== : 0.000318050384521484
map : 0.000821113586425781
map : 5.79357147216797e-05
map7: 3.00407409667969e-05
map : 5.10215759277344e-05
map7: 2.88486480712891e-05
map : 5.10215759277344e-05
map7: 2.62260437011719e-05
map : 4.98294830322266e-05
map7: 2.59876251220703e-05

計測に使用したコードはこちらにあげました。

なおコマンドラインから指定できるコンパイルオプションはこうなっているようです。

  -Onone                 Compile without any optimization
  -Ounchecked            Compile with optimizations and remove runtime safety checks
  -O                     Compile with optimizations

通常は-Onone が使われているようです。

まとめ

ひとまず今回の検証方法においては、標準のmapより速い実装が手に入りました。

ちなみに、Playgroundではこうなります。

map  : 0.181938886642456
map7 : 0.619832992553711

モヤっとしますね。

まだまだ不明点だらけで、勉強しないといけないことが山積みだということがわかりました。

以上です。

Swift arrays are not lists

第2回 カジュアル Swift 勉強会 @ 青葉台で簡単に共有した内容をまとめました。
当日迷宮入りしてしまった部分も調査を進めましたので、ご興味あればご確認ください。

背景

Advanced Swiftを読んでいたら、mapはreduceを使うと簡単に実装できるよね、ということが書いてありました。

extension Array {
    func map2<U>(transform: Element ->U) -> [U] {
        return reduce([]) {
            $0 + [transform($1)]
        }
    }
}

そして、次にこんなことが書いてありました。

Swift is not Haskell, and Swift arrays are not lists.

Swiftのreduceは毎回新しいarrayを生成するため、パフォーマンスが出ないよ、ということがいいたいようです。
ただ、Haskellと比較してどう違うんだ?とか、Swiftのarrayがlistではないというのはどういうことだ?とか気になって調べていたら、色々発見がありました。

本題

まずは、いろいろな方法で実装したmapの速度を1000件程度で測ってみました。

gist.github.com

以下、解説します。

map2

まずはreduceを使ってmap2を実装しました。このレベルだと体感は大して変わりませんが、数字で見るとやはり遅いようです。(Playgroundだとコンパイルオプションが違ったりするのか、なぜか劇的な違いが出ます。ぜひお手元のXcode7で試してみてください。)

map3

次に、reduceを使わないものをmap3として実装しました。for文を回してresultにappendするシンプルなものです。しかし、僅かに標準map に速度が及びません。
Arrayのcapacityをappendの度に拡張するのがパフォーマンスの障害になっているのでしょうか。

map4

そこで、init(count: Int, repeatedValue: Element) を使ってmap4を実装しました。
resultのcapacityをあらかじめ確保しておけば、appendの度にメモリ確保することはないので速くなるはず、という理論です。
勉強会当日はこのあたりの最適化の方法が不慣れで時間を取ってしまったのですが、なんとか動かせました。
でも数字を見ると明らかなように、遅くなりました。

map5

こうなったらもう意地です。Google先生にお願いしました。
検索でヒットしたこちらの記事を参考に、map5を実装しました。
なんとdispatch_group_asyncでバッチ実行しています。その発想はありませんでした。

しかし・・・いずれもよい結果がでませんでした。

まとめ

結局、なぜ私のコードが標準 map に追いつけないのか、いったい標準mapはどういう実装になっているのかといったことは、残念ながら私の力不足で謎のままとなってしまいました。

Swift is not Haskell, and Swift arrays are not lists.

この一文に含まれる意味を汲み取れれば、もう少し見当もつくのかもしれないなと思い、今日も「すごいH本」を手に取るのでした。

以上です。

LGTM Macアプリを作りました

f:id:toshi0383:20150905232356g:plain

既にTwitterには流してたんですが、開発者のみなさんの普段のLGTMのフローがよりスムーズになるMacアプリを作りました。ご活用ください。
単純に本家(?)のWebサイトのレスポンスが悪かったというのがモチベーションです。

アプリはこちらからダウンロードできます。
いま、AppStoreに申請しています。

みんなでわいわいいじれたほうが楽しいかと思って、下記にソースコードを公開しました。
issue、PR、Forkなどお待ちしてます。今後GitHub上では英語オンリーで行こうと思ってるんですが、issue(要望、バグレポなど)は日本語で書いてくれてもいいです。翻訳します。

github.com

技術的には、Swift2の新機能や各OSSのSwift2ブランチなどを試せて、いい機会でした。
Storyboard Referenceも使おうと思ったんですが、MacアプリだとOS X 10.11でしか動かないみたいで、開発マシンのバージョンをあげちゃうわけにもいかず断念。
StackViewは使ってみたんですが超絶ラクですね。オートレイアウトがとってもシンプルにできました。

Macアプリ自体初挑戦だったので、ViewControllerをいじりながら端末の回転を考えなくて良いという点が新鮮というかラクでした。
あとは、NSImageViewが勝手にアニメGIFをアニメーションしてくれて助かりました。
たぶんまだよくわかっていない部分がたくさんあるので、コードを見て気になったらぜひアドバイスください!

それでは。

360|iDev まとめ

セッションビデオとスライドなどが出揃った模様ですので、記事にしておきます。 下記にまとまって公開されています。

360idev.com github.com

それだけなんですけど、そういえば運営的な視点でまとめていなかったので軽く。

  • 参加者は392人
  • チケットは$899
  • スポンサーは1桁社(最終日朝のState of union というセッションで会計の収支が公開されてました)
  • トラックは最大6つ並行。すべて埋まっていたわけではない。

とか書いていたら下記に主催者の記事が上がってました。

360idev.com

ちょっと残念だった点は、

  • YAPC Asiaのように例えばAppleの中の人が来るみたいなことはなかったこと
  • ランチは会場近くの3箇所のお店から選んでランチチケットを持って行くスタイルで、かなり並んでしまっていたこと

もちろん上の記事にあるように、ランチで並んでいる間暇すぎるので他の参加者とコミュニケーションのきっかけになるというのはありました。実際私もサンフランシスコで働いているエンジニアから色々話を聞いたりすることができましたし。記事によると来年は6箇所に増やしたいとのことですけど、むしろランチセッションにして今半のお弁当配ってほしいなーなんて。無理な注文でしょうか。

そして、来年のチケットは値上げして$1299になるとか。うーむ。ますます個人だと行きづらくなってしまいますね。Indies Indies言っている割には、Indies参加できないというなんという矛盾。。
そう考えるとYAPC Asiaの品質はすごいと思いました。あれだけたくさんのトラックのイベントを2.5日間やってひとり1万以下だなんて!単純に物価!?いやいやそんなわけは。。

まあこのように運営の視点で行くといろいろ突っ込みどころが出てくるんですが、イベント全体としてはとても雰囲気が良かったですし、自分としてはiOS開発者として今年一番刺激を受けたイベントとなりました。参加して良かったですし、ぜひ来年も参加したいと思っています。

日本のイベントとの比較で行くと、英語圏なので、参加者が世界各地から集まっていたという点が、大きく違いますね。主催の記事にあるように、少なくとも12カ国から人が集まっていた、と。日本のイベントはどうしても日本で閉じがちなので、このあたりは日本のイベントの改善点ではないでしょうか。

こちらからは以上です。

360|idev にきています(3日目)

1日目
2日目

200: WHAT’S IN FOR US AFTER THE INDIEPOCALIPSE?

個人アプリの黄金時代が終わったいま、どうすればいい?という内容。
人気者のMarin Torodof 氏(さくじつのEasyAnimationの人)が発表してくれました。

Trodof氏も元々は少人数の仲間を集めて小さなアプリを作ってmake moneyしていたそうですが、最近うまくいかない、デザイナと2人でiOS8のカスタムキーボードを作ったけど、頑張りすぎて病院に担ぎ込まれたため医療費を経費として計上すると完全にマイナス。そんな逆境でワタシはどうしたか!?という、まあ最後は彼の成功エピソードという感じでしたね。

印象に残ったのは、「とにかく自分の好きなこと、やりたいことにフォーカスして、それ以外はやらないようにしたら、物事がうまく回るようになった」と言っていたこと。いわゆる「いい話」だと思うんですが、これは私もそうだと思っています。私はおそらく他のスーパーハッカーのような才能も経験もないですが、プログラミングが好きです。いまのこの環境があるのは常識とか現状にとらわれず、思い切ってそういうことに集中できそうな環境を探して飛び込んで行ったからだと思っています。たぶんあまり経験とかは関係なくて、いつでもなにかしら道はあるというか、そんなことを再確認させられるセッションでした。

人生一度きりですからね。

300: THE CHALLENGES OF BUILDING A DATABASE API (IN SWIFT)

Realmのgiddensさんの話。ゆるキャラでした。
RealmSwiftのAPIがどうしてああなったかというテーマで、とても興味深かったです。
SwiftがXcodeのバージョンごとに全然変わるので、Swift製ライブラリを書くのはまだちょっとツライ(Swift is not ready for 'this', Yet.)と言っていたのが印象的でした。
RealmSwiftは裏側ではがっつり(というかそのまま?)Objective-Cの機能を利用しているということで、XcodeのバージョンごとのSwiftサポートを入れるのが精神的にくるとか。

いまのところ、APIがきれいであるということ以外は、Realm(Objective-C)よりRealmSwiftが優れているということはないようです。性能については、Objective-C<=>Swiftの互換処理が挟まるため、当然Realm(Objective-C)より速くはない、と。structがもう少し動的になったりとかすればPure Swiftにできるかも、とは言ってました(たぶん)。
まあ実際個人アプリで使っている分には全く問題なく使えてますので、ライトユースにはRealmSwiftバンザイと思っています。

ちなみに会場で隣にいたデベロッパ(割とでっかいおっさん)に「Realm使ってる?」と聞いたんですが、「ちょっと見てはみたけど、まだCoreData使うかな。実績あるし。」といった回答。みんな大好きなRealmが本当にCoreDataやSQLiteを置き換えるまでには、USでもまだまだ時間がかかりそうな印象でした。
よく考えたらまだメジャーバージョン0ですしね。

UISearchController with a UICollectionView

POSSIBLE mobileという、会場のすぐ近くにオフィスがあるカイシャの人の発表。

UISearchControllerをUICollectionViewで使うには、というテーマ。
とても簡単に連携できるようでしたが、やはり若干のハマりポイントがあり、その解説も含めて発表してくれました。

サンプルアプリ。 github.com

なんというかアウトラインもしっかり書いてきてたし、バリバリのSIerという雰囲気があり面白かったです。
一緒に働く人を募集していますと言ってましたが、きっとバリバリ系なんだろうなー、とか勝手に想像。

STUMP 360 JR: NOT DEAD YET

何かと思ったら、ちょっとしたゲームの時間でした。2年前から始めたとか。
このイベントで登壇したパネリストがPCは持たずにステージに並んで、観客と双方向にAppleiOSに関する問題を出題して、多く正解したほうが勝ちという、アメリカ人が好きそうなやつでした。結構観客からもコアな出題があったりして、盛り上がりました。観客は問題を見てからググったりしていいけどパネリストはググるの禁止という厳しいルールなんですが、さすがパネリストはエキスパートなので、「知らねーし」みたいな問題もスラスラ答えていました。ああいうのをオタク(horrible geek)というんだな、と思いました、冗談です。

TUESDAY RECEPTION

今日は元気だったので、レセプションにも軽く参加してきました。
私の場合、USのdev事情ってほとんど(Rebuild.fmくらいしか)ソースがないので、こういった懇親会は本当に有益でした。
なんかフランクなノリでライトなオファーをいただいたような気がするようなしないような。。インド人安いけど品質だめだから次は日本かな、とかになるんですかね。あっちにくらべたら日本は単価安いみたいですし。円安エ。。
今日知り合った方だと、ロンドン、サンフランシスコ、シリコンバレー、ブラジル、デンバー(地元)と、本当に世界各国から集まっている感じでした。
まだ、私と同じように日本から来ている人には会っていないです。

まとめ

今日は参加セッションを少なめにしたので、その分中身が濃くなりました。いやはや。
明日は最終日!

360|idev にきています(2日目)

Home - 360|iDev
1日目に続いて、2日目のレポです。

蓋を開けてみるとどうも1日目はおまけだったようで、一番最初にkeynoteがありました。
短いセッションが目白押しで、1日目とは違う体力を使いました。

STILL HERE

keynote。 ジョブスのパロディやら「"アプリ開発"を音とフレーズで表現してみた」というパフォーマンスなどがあり、、
すみません写真でもとっとけばよかったですね。

まあそれは置いておいてこのセッションでは、「AppStoreは市場が成熟しており個人作成のアプリで戦うことがなかなか難しいという現状を踏まえて、今後おれたちはどうしていけばいいのか?"Is indie dead ?"」というトピックについて、プレゼンターが熱く語っていたのが印象的でした。やっぱりiOS devやるなら自分のアイディアで一発当てようぜ的な雰囲気がありますね。フロンティア精神というやつなのでしょうか。

どういうタイミングでリリースするべきかとか、アプリで収益を得るということについて役に立つ情報満載でした。

「Jobsは"Think different"という言葉が有名だけど、Appleがどんどん市場で成功してきているときは、"Think Apple"は"Think different"にはならないからな。」というのは、ナルホド納得。

Indieでやるにはコストかかりすぎて片手間でできないのでは?という問いに対しては、とにかく「Quit Twitter, quit Facebook, quit playing social games, stop watching TV, limit internet use.」という返答。自分の時間もっと大事にしろよ、と。ハッとして即Twitterアプリ消しました。(影響されやすい)

300: SOLVING AUTO LAYOUT PROBLEMS

AutoLayoutでのハマりどころについて丁寧に解説してくれました。
ScrollViewでのAutoLayout、self-sizing-tableview、制約のconflictが起きたときのデバッグ方法など。

コンソールのエラーログも読み方を教えてもらったので、今日からちゃんと読もうと思いました。

100: LOCALIZATION EXPLAINED

AppStoreのユーザのうち41%は中国と日本ということで、今後さらに重要なテーマになっていくと思っていますが、やはり後回しになりがちなのがこちら。
Localizationする際のポイントをわかりやすく解説してくれていました。
シカゴにある会社からみんなできているということで、シカゴもStartup多いのかしら、とちょっと気になりました。

先日のpotatotipsでクックパッドの方がたしかこのトピックで話されていましたが、こちらのセッションでは英語圏のアプリをいかに異なる文化に適用していくか、という視点で、めっちゃ早口の英語で語られていた点が新鮮でした。

Accessibility LabelもLocalizeするの忘れないでね!と補足するあたりさすがだなと思いました。

サンプルアプリ

github.com

100: BEYOND WHITE: EMBRACING THE IOS DESIGN AESTHETIC

デザイナからエンジニアに転向した系の人。はだしで発表していました。

以前の職場でのブラックな話とかきけてなかなか興味深いセッションでした。

プロトタイプするときはクレヨンと画用紙!ファッキンPCから離れろ!とか言っていておもしろかった。

100: MAKING A LIVING IN AND OUT OF THE APP STORE

いかに個人アプリで戦うか?という話。
勉強になったけどよく考えたらたぶんコンサル会社の宣伝セッションだったのかな、とも。

200: CORE ANIMATION FOR THE MASSES

歴戦の猛者といった風格のシニアエンジニアの方の発表でした。
日本で普段参加する勉強会って結構若手が多い感じがしていたのですが、このイベントは普通に現役でやっているベテランの方が登壇していて、大変刺激になります。
正直この辺りで体力を使い果たして何言ってるかわからなかったんですが、サンプルアプリ見てるだけでもとても勉強になります。
ホテルで仮眠をとってからはずっとこれで遊んでました。

github.com

BEYOND WHITEの人も言ってましたが、せっかくUIKitやQuartz(CoreAnimation)といった"おもちゃ"が用意されているので、しっかり使いこなして活用していきたいですね。

まとめ

2日目はここまで!