iOSDC Japan 2024に参加してきました
はじめに
2ヶ月連続でブログ投稿時に風邪を引いているかむい(@kamui_project)です…
今年もiOSDC Japan 2024(以降: iOSDC)に参加して来ました。弊社で自分がiOSDC参加ブログをまとめるのもこれで4回目となり、参加するのと合わせてOutputするのも恒例となっています😌 今年も#iwillblogの精神でまとめていきたいと思います。
準備してきたこと
前回の投稿ではiOSDCのスポンサー協賛について書いたのですが、その際iOSDCチャレンジトークンを記載し、多くのiOSDC参加者に閲覧して頂くことができました👏 また来年も実施できたらと思っています。
こちらでは合わせて過去のiOSDC参加ブログも紹介しているので、是非読んで頂けると嬉しいです。
また今年も、iOSDCのパンフレットに弊社を紹介するデザイン制作を実施しました。今年リリースしたアバター2.0機能の紹介でも使われているもので、さまざまな体型・顔付きを表現できる#なりたい自分で、生きていく。にふさわしいデザインに仕上がっています。
今年のiOSDCでは弊社のチュイ(@chuymaster)がLT枠で登壇をしました。
当日の発表内容について感想や補足を頂きました🎤
ライブ配信サービスのための自動字幕起こし機能の実装と課題解決
字幕起こし機能の解説と、実装時に数日ハマった落とし穴の回避方法について話しました!
iOSのAPIを使った際、挙動が分かりにくいときが結構あります。この事例を通して、実装時の注意点を伝えることができたんじゃないかなと思います。
初めてのiOSDCでのLT登壇でしたが、動画の後の拍手だったり、ペンライトでの応援だったり、とても楽しかったです!ありがとうございました!
ありがとうございました!👏
では続いて、自分が参加したセッションについてまとめていきたいと思います。
健康第一!MetricKitで始めるアプリの健康診断
iOS13から登場したMetricKitの基本的な使い方や、実際の活用事例について紹介するセッションでした。スクロールのカクつきや応答性の悪さ、バッテリー消耗など、目に見えにくい不具合がユーザーの不満を招き、アンインストールされてしまうことを防ぐためにも、ユーザー環境でアプリのパフォーマンスデータを収集し、クラッシュの内容を継続的にモニタリングする方法について紹介してくれました。
序盤はMetricKitの他にパフォーマンス情報を収集できるXcode OrganizerやFirebaseのPerformance Monitoringを合わせて紹介し、それぞれの得意不得意を1つの表に書きまとめてくれたのが良かったです。わかりやすい👏
その次にMetricKitの基本情報や取得できるデータについての紹介があり、アプリの起動時間・異常終了・フリーズを見ておくべき観点として話し、それらをMetricKitで取得できることを実際の取得値とグラフを用いて紹介してくれました。
活用事例については、FirebaseのCrashlyticsやTestFlightでクラッシュログが見当たらないクラッシュの問題があり、原因を探るとメモリリークのバグがあったとのことでした。
そのため、MetricKitで取得したデータを非致命的エラーとしてCrashlyticsに送信するという対応をされたそうです。そのままMetricKitで実現しようとするとバックエンドを用意するコストも考慮しなければなりませんが、Crashlyticsを活用するアイティアはとても良いと思いました。
弊社でもクラッシュログの計測にCrashlyticsを利用しているため早速導入してみました。メモリ制限が超えた時のクラッシュも確認が出来たので、早速活用していけそうです👏
Mastering AsyncSequence - 使う・作る・他のデザインパターン(クロージャ、Delegate など)から移行する
Swift5.5で登場したSwift Concurrencyと合わせて導入されたAsyncSequenceについて紹介されたセッション。非同期処理やイベント処理にはクロージャやDelegateが使われてきましたが、AsyncSequenceに移行が進んでいて、他の新しいAPIでもAsyncSequenceが採用されているとのことです。そんなAsyncSequenceの基礎や他のデザインパターンからの移行方法、メリット、注意点を紹介してくれました。
まず身近な型であるDictionaryやArray, Stringらが準拠しているSequenceの非同期版がAsyncSequenceであり、カスタムなSequenceがどのようにシーケンシャルな処理を実現するかを参考例に、AsyncSequenceの実装を紹介するパートがとても簡潔でわかりやすかったです。
また失敗するケースもAsyncSequenceはサポートしており、その場合はfor try await in構文が使えるとのことでした。
続いて、Apple SDKのAPIでもAsyncSequenceを利用してる箇所が年々増えており(Xcode16では約90あるとのこと)、主に新規のAPIで登場するものと、既存のAPIでクロージャやDelegateなどで担っていた部分をAsyncSequenceに置き換えたものがあるみたいです。
それらのAPI同様に、我々がこれまで利用してきたクロージャやDelegateをどのようにAsyncSequenceに置き換えられるかの実用方法を紹介してくれました。以下はwithCheckedContinuationのクロージャの置き換え例ですが、呼び出し1回につき返す値が1つのみのため、呼び出しが時間的に複数ある場合はクラッシュしてしまうとのことで、AsyncThrowingStreamを使い解決するやり方を話してくれました。
そして実際にiOS Applicationに導入するにあたって考慮すべき命名・実装場所・cancelの重要性・メモリリークの可能性についてまとめてくれました。このメモリリークの可能性の中で、NotificationCenter.default.notificaftionsを例に挙げ、Taskのクロージャがselfでうっかり強参照でキャプチャされる可能性について言及されていました。厳密に対応しようとすると、コードの静的解析にかけて検知する仕組みを用意するなどが挙げられますが、暗黙的にselfがキャプチャされるパタンを網羅的に対処するのは骨が折れるため、文法的に回避するライブラリを自作されたとのことで、そちらのコードを紹介してくれました。
Combineのsinkと同じインターフェースを持っており、actorコンテキストは継承しながらも暗黙的なselfの強参照を行えない仕組みとのことです。
Mergeable Libraryで高速なアプリ起動を実現しよう!
Xcode15から利用できるMergeable Libraryについて、従来のDynamic/Static Libraryとの比較をし、Mergeable Libraryはその両方のメリットを活かすことができる仕組みについて紹介するセッションでした。その利点や導入方法、新しいプロジェクト構成についてまとめてくれています。
まずアプリ起動に時間がかかるデモアプリ(起動に15秒…!)を用意し、その原因として1000個のアプリターゲットで構成されている巨大アプリであることを挙げていました。
そのアプリの起動時間が遅くなるメカニズムについて、モジュールが含まれたフレームワークとリンクの仕組みをおさらいを兼ねて紹介し、従来のDynamic/Static Libraryについて利用時のメリット・デメリットをまとめてくれました。
この従来の方法では、開発者体験とユーザー体験とを天秤にかける形でメリット・デメリットが綺麗に分かれており、またデバッグ・リリース間でビルド設定が異なるため複雑になる他、リソースバンドルの扱いについては、Bundle(for:)のランタイムの挙動が双方で変わってしまうという難しさも紹介していました。
これらの問題を解決するために登場したのがMergeable Libraryで、従来の2つのライブラリの良いところを合わせさった振る舞いを実現してくれるとのこと。
そのため導入さえすれば、アプリのビルド時間問題は解決するのかと思われたのですが、確認すると数値は理想値とはほど遠く、その要因について考察していきました。
デモアプリではアプリターゲットが1000個あったため、Dynamicフレームワークを抽出し、それをReexported Binariesとして再エクスポートする処理のところで、通常ではそれほどではないコピーコストが無視できなくるほど時間がかかっていたためだということがわかりました。
そこでマージされるフレームワーク側の設定値であるMAKE_MERGEABLE=YESを行うと、フレームワークを再エクスポートせず、1つのDynamicライブラリにDynamic フレームワークのバイナリがマージされるためReexportedBinariesが出力されなくなり、コピーコストを無くすことが出来るとのこと。
しかしまだ理想値に届かず、想定したアプリの仕組みでの確認ではないため参考値としつつ、是非皆さんには導入後に事例をコミュニティに共有してほしいとのことでした。この知見を活かして、世界中のアプリの起動時間が改善されると良いですね🚀
ここまではこれまでも利用できた機能についての発表をまとめてみました。
そして今年は、その中でもSwift6で登場する機能について紹介するセッションも注目されていました。
座談会 「Strict ConcurrencyとSwift 6が開く新時代: 私たちはどう生きるか?」
Strict Concurrencyチェックによるデータ競合防止についてのセッション。Swift 6に向けたコードの安全性と開発効率を大幅に向上させる大きな変革ですが、コード変更が必要な場合対応が課題となるため、座談会形式で、スムーズに移行するための移行方法やタイミング、注意点を話してくれました。
ちなみにこちらの内容は雑誌ソフトウェアデザインにも今後掲載予定とのこと。
まずStrict Concurrencyチェックを理解する上で欠かせないSwift Concurrencyについてアンケートを募り 学習コストがかかる(かかりそう)・難しい(難しそう) という意見が多くあげられていました。それに対し「それは正しい」「一方でそれを使ってアプリを作ること自体はそれほどではない」という説明から始まりました。
次に認識合わせについて、Swift ConcurrencyはData race(データ競合)を防いでくれる ※Race condition(競合状態)を防いでくれるではない という話をし双方の違いを比較しながら解説。
そしてコードも交えながらの用語解説へと続きます。
アンケートの中から「isolationがわからない!」という質問について、全部の変数が隔離境界を越えられるわけでは無いと指摘し、隔離境界を超える条件と、isolationの書き分けを一覧化し説明していました。ただし現段階ではpropoasl上draftなものが多く、使えないため理解することが難しいとのこと。
そしてComplete Strict Concurrencyへの移行戦略について。事前アンケートでは対応箇所が明確になったなど良い点を上げる一方で、警告が多すぎて途方に暮れる・警告かバグかの違いがわからないなどを難しい点として上げられていました。
途方に暮れるという意見については、Swift登場時のOptional対応と似ていて、これまで気にしないで書いていた既存コードでうまくいかない部分の書き直しが必要になるのは仕方ない上で、全部無理につけ直したりはせずとりあえず確認できる方法で進めていった様に、今回も自然に進んでいくものだと。また一旦リファクタリングしたいという欲求に駆られると思うが、まず抑えて、このマイグレーションをやり切った後でリファクタリングというプロセスをAppleが話しているという補足がありました。
iOS開発に適したSwift Concurrencyの使い方はあるのか?という質問のパートとなり、隔離境界を越えてはいけない値が越えてしまうという本質的な部分の指摘がありました。その中で、隔離境界を作らなければエラーは起きないという点にも触れ、iPhoneアプリのようなGUIアプリを作る場合はそんなに問題にならないように作れるとしました。
具体的には、MainActorの領域の中でデータのやり取りをしてる分には隔離境界は超えないとし、逆にMainActorでやれば良いところを不必要にMainActor外でやっている処理を極力無くすことで、隔離境界を超える問題を抑制できるのではと話していました(不必要に全部をMainActorでやれば良いという話ではないという前置きの上で)。
さいごに
今年も昨年同様、iOSDC共有会を社内で実施し、各々が見たセッションの概要を説明しながらメンバー間で発表内容と感想を共有し合う時間を作っています。
見逃していたセッションの知見も得て、改めてセッションのタイムシフトを見返そうと思える良い共有の場です。
そして例年ニコ生にてオンライン開催をしているiOSDCですが、株式会社KADOKAWAを標的としたサイバー攻撃による影響で、ニコニコ動画が一時利用できないニュースがiOSDCを控える夏に起きました。今年はオンライン開催は大丈夫かな…と思いましたが、無事ニコ生での視聴が実現できiOSDCの運営以外の方達にも感謝をしきれない開催となりました😌
来年こそは、久々にオフラインで参加し、交流のある社外のiOSエンジニアの人たちとビール片手に話し合いたいなと思いました🍻そしてiOSの新機能をREALITYに導入し、その知見を発表できる機会を得られるよう頑張っていきたいと思います。