フューチャー技術ブログ

iOSDC Japan 2024に参加してきました!

はじめに

HealthCare Innovation Group(HIG)1の橋本です。

初めてiOSDC Japan 2024にオフライン参加してきました!

参加報告として、いくつかのセッションとその内容を紹介したいと思います!

iOSDC Japanとは

国内を中心に多くのiOS開発に関わる多くの人々が集まるiOSのDeveloper Conference(開発者会議)です。

公式サイトの説明は次のようになっており、技術的な話題から開発者同士の繋がりを持てるパーティや懇親会などの様々なイベントがあります。

iOSDC Japan 2024はiOS関連技術をコアのテーマとしたソフトウェア技術者のためのカンファレンスです。今年もリアル会場とオンライン配信のハイブリッド開催を予定しています。
日本中、世界中から公募した知的好奇心を刺激するトークの他にも、パンフレットに掲載された技術記事、自分のペースでゆっくり参加できるポスターセッション、気持ちを盛り上げるネイルアートやフェイスペインティング、オープニングパーティ & 懇親会などなど、初心者から上級者まで楽しめるコンテンツがみなさんを待っています。
8月22日(木)〜 8月24日(土)はお祭りです!お楽しみに!!

公式HP: https://iosdc.jp/2024/

特に気になったセッションの紹介

視聴したセッションの中で、印象に残ったものの紹介と感想を記載します。

  • 座談会 「Strict ConcurrencyとSwift 6が開く新時代: 私たちはどう生きるか?」 by shiz
  • MV State PatternでSwiftUIを受け入れる by Hiroma Tsuchiya
  • Swift 6のTyped throwsとSwiftにおけるエラーハンドリングの全体像を学ぶ by koher

座談会 「Strict ConcurrencyとSwift 6が開く新時代: 私たちはどう生きるか?」 by shiz

発表資料: https://speakerdeck.com/shiz/zuo-tan-hui-strict-concurrencytoswift-6gakai-kuxin-shi-dai-si-tatihadousheng-kiruka

発表概要と感想

iOS界隈の強強エンジニアの方々の座談会で、Swift6への移行に向けてのStrict Concurrency対応についてお話されていました。

Swift 6では、Actorを使ったデータ競合防止の仕組みがさらに強化されます。特に、Actor間で扱うデータの安全性がコンパイラで厳密にチェックされるため、既存のコードがコンパイルエラーとなる可能性があります。これにより、並行処理の安全性が一層向上しますが、我々はコードの修正が必要になってくるケースがあります。

『いつまでにStrict Concurrency 対応をするべきか。』
この問いに答えとしては、Xcode 16でもSwift5言語モードを利用可能であるため、ひとまずは直ぐにコンパイルエラーまみれになって急に動かなくなるということは避けられそうです。

この座談会でお聞きして、Swift6への移行に向けて以下の知識をしっかりと理解する必要があると感じました。

  • Swift Concurrency
    • Sendable
    • Actor
    • isolation

私や開発チームとしては、Complete Strict Concurrency Checkを使って、まずは既存のコードでSwift6にあげるとどこがコンパイルエラーになるかを洗い出しをするところから作戦を立てて行きたいと思います。

本セッション内で紹介のあった事例別!Strict Concurrency対応方法やSwiftコミュニティのSwift6へのマイグレーションガイド(Migrating to Swift 6)を参考にしたいです。また、日本語訳版についてもSwift 6への移行も既にまとめて頂いており、めちゃくちゃありがたいです。また、次のApple公式ドキュメントやサンプルコードも参考にしたいと思います。

MV State PatternでSwiftUIを受け入れる by Hiroma Tsuchiya

発表概要と感想

発表内容は、MV State Patternというアーキテクチャに関する説明と、採用理由とその実装方法について紹介しているセッションでした。

MVVM x SwiftUIの組み合わせで感じた違和感

発表者の開発チームでは、MVVMとSwiftUIでの開発経験がありその中でいくつかの違和感や課題を感じていたとのことです。
具体的に、感じていた違和感は次の2つがあったとのことです。

  1. ViewModelを精密に構築するほど、SwiftUIフレームワークの機能(各種プロパティラッパー)を捨てるというジレンマがあった
  2. データバインディングの機能はSwiftUIにおいてすでにViewに組み込まれているため、UIKit時代の役割のままViewModelを持ち込む必要性に疑問視

2.に関して、発表者の話にあったようにSwiftUIはそもそも@Stateや@Binding、@ObservedObjectなどを使うことで、ビューとデータの間に自動的な連携が行われれる機能がありますし、状態が変わればUIが更新され、UIでユーザーが入力した内容がデータに反映される、という関係が自動的に保たれているので、ユースケースによってはViewModelの必要性は低くなることには納得しました。

また、Apple公式ドキュメントでも、次のように言及されています。

https://developer.apple.com/documentation/swiftui/monitoring-model-data-changes-in-your-app

Traditionally, you use a view controller to move data back and forth between the model and the UI, but SwiftUI handles most of this synchronization for you. To update views when data changes, you make your data model classes observable objects, publish their properties, and declare instances of them using property wrappers.

MV State Patternとは

Appleの公式ドキュメントやサンプルコードで使われていたアーキテクチャに対して、開発者コミュニティがMV State Patternと名前をつけてあげたアーキテクチャみたいです。
このMVState Patternのデータフローパターンのコンセプトは次のようになっています。

  • SwiftUIがどのように、StateとViewを結びつけているかという構造と全く同じです。具体的には次のような特徴を持ちます。
    • ユーザーがアクションを実行することで状態が更新され、再レンダリングを起こす
    • 単方向のループのように動作し、状態が更新されればいつでも新しいバージョンのViewが作られる
    • ユーザーの入力に限定されず、タイマーや通知などの外部からの状態変更もループに組み入れられる

これは、WWDC2019のData Flow Through SwiftUIのセッションで登場した図と同じ内容です。

https://developer.apple.com/videos/play/wwdc2019/226/

Viewにバリデーションや特定のコンポーネントにのための処理を含み、MVVMでいうViewModelの役割も持ちます。しかし、ViewModelで書くような処理をすべて、Viewに持たせるため、コードが長くなる傾向がありました。

Viewが大きくなることに対する対応策

  1. MARKの活用

    • Main View, SubView, ViewLogicを次のようにコード上に目印として記載する。(ミニマップからMARKの箇所に飛べるのも便利。)


      // MARK: MainView
      ...
      // MARK: SubView
      ...
      // MARK: ViewLogic
      ...

  2. ViewからViewLogicへ切り出す

    • メリット: Viewプロトコル準拠ではなくなるため、テストコードも容易にかける

      final class SomeViewLogic {
      ...
      init(...) {
      }

      var title: String? {
      ...
      }
      }

MV State Patternのメリット・デメリット

主なメリットは、SwiftUIのシンプルさに従ったアーキテクチャであることによる学習コストの低さとシンプルさであり、
デメリットは、(MVVMと比べると、)プレゼンテーション層の関心の分離が甘く、境界が曖昧になりやすいこととの紹介がありました。つまり、Fat Viewに陥る可能性が高いといえます。先程紹介したように、この問題には、MARKの活用とViewLogicへの切り出しを行い、コードをクリーンに保つ必要があります。

Viewが大きくなることに対する対応策は、アーキテクチャの種類にかかわらず、Fat-viewに対応する方法として有効であるため、私の関わるアプリにおいても参考にしたいと思いました。

Swift 6のTyped throwsとSwiftにおけるエラーハンドリングの全体像を学ぶ by koher

発表資料: https://speakerdeck.com/ridwy/kong-jian-bideohuomatuto-mv-hevcgaxie-sicuo-rushi-jie

発表概要と感想

こちらのセッションでは、Swift 6から導入されるTyped throwsとSwiftにおけるエラーハンドリングの全体像を知ることができました。

ここでは、発表内容から大変わかりやすかったTyped Throwsが解決する問題とその解決方法を簡単に紹介したいと思います。

Untyped throwsの問題

これまでのthrowsのUntyped throwsの問題点を解決する方法として、Typed throwsが導入されます。

次のようなparseIntを関数をエラーハンドリングする例を考えます。

// Stringを受け取って、Intを返す関数
func parseInt(_ value: String) throws -> int
if value.isEmpty {throw ParseError.emptyValue }
guard let number = Int(value) else {
if value.contains(/^[-]\d+$/) {
throw ParseError.outOfBounds(value)
} else {
throw ParseError.illegalFormat(value)
}
}
return number
}

enum ParseError: Error {
case emptyValue
case illegalFormat(String)
case outOfBounds(String)
}

上記の関数をdo-catchを使ってハンドリングすると次のようになります。

// ハンドリングする側
do {
let number: Int = try parseInt(string) // ParseErrorしか返さない関数
print(number)
} catch {
print(error) // 暗黙のerrorはany Error型になってしまう。
}

この書き方だと、catch節の中のerrorany Error型となってしまいます。
次に、ParseError型でハンドリングするように書き直します。

ParserErrorハンドリングできるように、変更

//
do {
let number: Int = try parseInt(string) // ParseErrorしか返さない関数
print(number)
} catch let error as ParseError {
switch error { // ParseErrorを返す
print(error) // any Error型になってしまう。
case .emptyValue: ...
case .illegalFormat(let value): ...
}

しかし、このコードだとcatchが網羅的ではないよと次のエラーがでます。

 Errors thrown from here are not handled because the enclosing catch is not exhaustive

parseInt()ParseErrorしかthrowしないが、コンパイラからはそれがわからないため、あらゆるエラーをスローすると判断します。catch節でParseErrorをハンドルしているが、コンパイラ側からはany Errorが投げられると判断され、網羅的ではないよとエラーがでます。これのワークアラウンドとして次の方法があります。

// ParserErrorハンドリングするように`preconditionFailure()`を追加するように、変更します。

do {
let number: Int = try parseInt(string) // ParseErrorしか返さない関数
print(number)
} catch let error as ParseError {
switch error { // ParseErrorを返す
print(error) // any Error型になってしまう。
case .emptyValue: ...
case .illegalFormat(let value): ...
}
} catch {
preconditionFailure("Never reaches here.")
}

これがUntyped Throwsの問題であり、これを解決するのがTyped Throwsになります。

Typed throwsによる上記の問題の解決方法

Typed throwsでは、さきほどの関数parseIntを次のようにして、エラーの型を指定できるようになります。

func parseInt(_ value: String) throws(ParseError) -> Int
do {
let number = try parseInt(string)
print(number)
} catch {
switch error { // typed throwsにより、any Error型ではなく、ParseError型を解釈できるようになる。
...
}

最後に、Typed throwsはswift-evolution上で安易に使うべきではないと繰り返し記載されているので、本当に使う必要があるのかをよく考える必要があることを学びました。swift-evolutionのwhen to use typed throwsの内容を確認してみたいと思います。

本セッションでは、安易に使うべきではない理由として次の2つが挙げられていました。

  1. エラーの型は変化しやすい
  2. エラーが網羅的にハンドリングされることは少ない

Typed throwsの詳細を確認したい方は、次のswift-evolutionのSE-0413: Typed throwsを確認してみてください。

また、Typed throwsのお話だけではなく、後半のエラーハンドリングの全体像のお話は大変参考になりました。
エラーハンドリングの考え方が詳しく記されている次のドキュメントをもとにお話をされていましたので、時間があるときに目を通しておきたいと思います。このドキュメントは、swift2がリリースされたときの公開されたもののようです。

エラー処理を書くときに全体像を一度思い出して、この書き方で良いだろうかと自問自答したいなと思いました。koherさんがiOSDC2017年のセッションiOSDC Japan 2017 09/16 Track B 11:20 / 具体例とクイズで学ぶ、Swiftの4種類のエラーの使い分け / Yuta Koshizawaでも同じようにエラーハンドリングの全体像のお話をされていたので、こちらも合わせて視聴することをおすすめします。

上記以外で面白かった、参考になったセッション

Appleの新しいプライバシー要件対応:ノーコード アプリプラットフォームの実践事例 by Nao-RandD / ナオランド

私自身、担当している案件でプライバシーマニフェスト対応を進めており、再度プライバシーマニフェストの対応方法について歴史や今後についてまで紹介されており大変参考になりました。

発表資料: https://speakerdeck.com/nao_randd/applenoxin-siipuraibasiyao-jian-dui-ying-nokodoapuri-puratutohuomunoshi-jian-shi-li

ヤプリさんのテックブロクにもプライバシーマニフェスト対応について大変詳しく記載されているので、これからプライバシーマニフェスト対応を進める方にはとても参考になると思います。

現状は、プライバシーマニフェストのApple側のレビューはそこまで厳しくないようなので、今後段階的に厳しくなっていく可能性もあると思うのでプライバシーマニフェストに関する動向は引き続きウォッチしていきたいと思います。

空間ビデオフォーマット、MV-HEVCが写し撮る世界 by なめき ちはる

Apple Vision Proでの空間ビデオフォーマットについてやどうやって立体視を実現しているかなど、人の目の仕組みにも触れていてとても興味深いセッションでした。

これからの時代の新標準!Apple製テストフレームワーク「SwiftTesting」への移行とトラブルシューティング

新しいテストフレームワークSwiftTestingの概要とXCTestからの移行作業についてお話されていて、大変参考になるセッションでした。

移行作業の全体像だったり、XCTestをSwiftTestingの記法に置き換えてくれるツール(giginet/swift-testing-revolutionary)も知れたので、大変有意義な5分間でした。

発表資料: https://speakerdeck.com/uetyo/korekaranoshi-dai-noxin-biao-zhun-swifttestinghenoyi-xing-totoraburusiyuteingu

医療アプリ開発の最前線 - 安全性と生産性の両立への挑戦 by Shogo Yoshida

医療アプリ開発を通じて得た安全性と生産性の両立に関する知見を共有頂いたありがたいセッションでした。

具体的には、次のような知見が紹介されました。

  • 継続的なリファクタリングに取り組みつつ、Architecture Decision Record(ADR)を残すこと
  • トランクベース開発を採用
  • OpenAPI Generatorを使ったAPI仕様に合わせたリクエスト、モデルのコードの自動生成
  • Renovateを使用してライブラリの自動アップデートの管理
  • テスト自動化サービスMagicPodの活用

やはり、品質を高めつつ、生産性を高める方法は自動化することがとても大事だなとしみじみ感じました。

発表資料: https://speakerdeck.com/medley/yi-liao-apurikai-fa-nozui-qian-xian-an-quan-xing-tosheng-chan-xing-noliang-li-henotiao-zhan

さいごに

はじめてオフライン参加した今年のiOSDCは、現地参加ならではのコンテンツを楽しめたり、Xで会話したことがあるiOSエンジニアの方にお会いしてお話ができたりできたと、とても有意義な時間でした。

また、他の企業さんのプロダクトのコードをアンカンファレンスで、実際に見させて頂く機会をもらったり、貴重な経験ができました。

2025年は私自身なにかしらの形でiOSDC Japanに貢献できればと思っています。今から来年のiOSDC Japan 2025が楽しみです〜!

参考リンク


  1. 1.医療・ヘルスケア分野での案件や新規ビジネス創出を担う、2020年に誕生した事業部です。設立エピソードは未来報の記事をご覧ください。