iOSDC Japan 2023 での中島の発表資料です。
@motoshima1150iOSDC 2023SwiftUIの進化についていくためにやったこと
View Slide
このセッションのねらい『スタディサプリ 中学講座』がSwiftUIと共に歩んできた道を振り返りました。ポイント1 直面した課題の例として具体的にAlert, NavigationViewの進化を知るSwiftUIのような進化の早いフレームワークとどのように付き合うのかを考えるポイント2
Agenda | 01020304発表者紹介SwiftUIと『スタディサプリ 中学講座』SwiftUIの実践的な書き換えまとめ
発表者紹介01
@motoshima1150 / 中島元成- iOS アプリエンジニア- 『スタディサプリ 中学講座』開発を担当- 🍺, 🏕, "3dメガネ アイコン" by DesignBolts is licensed underCC BY 4.0
(株)リクルートでの位置づけ創業本社事業の売上収益従業員数2012年 10月1日株式会社リクルートホールディングス設立時の分社化により設立2018年 4月1日株式会社リクルートに商号変更東京7,606億円(2022年4月1日~2023年3月31日)19,836人(2023年4月1日現在 / アルバイト・パート含)OUR VISION
サービスラインナップ様々なサービスラインナップにて事業展開をしていますスタディサプリ対象学年 小・中学校 高校 大学・社会人オンラインビデオ(B to C)オンラインビデオ&アセスメント(B to B to C)オンラインコーチング パーソナルコーチプラン
SwiftUIと『スタディサプリ 中学講座』02
SwiftUI 年表 と『スタディサプリ 中学講座』WWDC19 WWDC20 WWDC21 WWDC22 WWDC23SwiftUI発表SwiftUIベースのアプリ構築が可能にListや検索の大幅強化.searchable modifierの追加.refreshable modifierの追加.swipeActions modifierの追加NavigationStackの追加Charts フレームワークの追加Photos フレームワークの追加KeyframeAnimation@Observable の追加MapKit の強化SwiftDataのサポートリニューアルリリースリニューアル開始
『スタディサプリ 中学講座』はSwiftUIと共に歩んでいる
どのような課題が発生したか● 既存実装が非推奨となり、将来的に廃止されてしまう○ Alert, NavigationLink● 新規APIが公開されるが、対応バージョン要件を満たせず導入できない○ NavigationStackAlert, Navigationのケースで書き換えをご紹介いたします
…『スタディサプリ 中学講座』の構成スタディサプリ 中学講座 projectCore: 依存関係や共通処理を持つUIComponent: 共通UIやDesignSystem の token などを持つJuniorHighSchool: 実際の画面単位でサブモジュールを用意MyPageStudyReport…マルチモジュール構成に移行中。各モジュール間は独立した実装が可能になっています。 コラム
SwiftUIの実践的な書き換え03
@State private var showAlert = falsevar body: some View {Button("Tap to show alert") {showAlert = true}.alert(isPresented: $showAlert) {Alert(title: Text("Current Location Not Available"),message: Text("Your current location can’t be " +"determined at this time."))}}struct Login: View {すprivate var didFail = falselet alertTitle: String = "Login failed."var body: some View {LoginForm(didFail: $didFail).alert(alertTitle,isPresented: $didFail) {Button("OK") {// Handle the acknowledgement.}}}}● Alert viewが廃止となり、より扱いやすくなっている。Alert の進化iOS 13.0–17.0 DeprecatediPadOS 13.0–17.0 Deprecatedhttps://developer.apple.com/documentation/swiftui/iOS 15.0+iPadOS 15.0+
『スタディサプリ 中学講座』でのAlert用途● ユーザーに向けて通信エラーを伝える● 学習を離脱するなどのユーザー状態が破棄される前の確認● 強制バージョンアップやメンテナンスなどの強制力の強いユーザー告知
Alert の書き換え.background(EmptyView().alert(isPresented: $isFirstAlertPresented,content: {Alert(title: Text("First alert"), message: Text("Alert message"))})).alert("First alert",isPresented: $isFirstAlertPresented,actions: { },message: { Text("Alert message") })旧APIでは1つのViewに対して、複数のAlertmodifierを付与した際に表示されない動作の回避として利用
NavigationViewNavigation APIの進化iOS 13.0–17.0 DeprecatediPadOS 13.0–17.0 DeprecatediOS 16.0+iPadOS 16.0+@State private var isShowingPurple = false@State private var isShowingPink = false@State private var isShowingOrange = falsevar body: some View {NavigationView {List {NavigationLink("Purple", isActive: $isShowingPurple) {ColorDetail(color: .purple)}NavigationLink("Pink", isActive: $isShowingPink) {ColorDetail(color: .pink)}NavigationLink("Orange", isActive: $isShowingOrange) {ColorDetail(color: .orange)}}}.navigationViewStyle(.stack)}// Nothing on the stack by default.@State private var path: [Color] = []var body: some View {NavigationStack(path: $path) {List {NavigationLink("Purple", value: .purple)NavigationLink("Pink", value: .pink)NavigationLink("Orange", value: .orange)}.navigationDestination(for: Color.self) { color inColorDetail(color: color)}}}https://developer.apple.com/documentation/swiftui/migrating-to-new-navigation-typesNavigationStack
『スタディサプリ 中学講座』でのNavigation用途● Push遷移(2−3階層)● プログラムで制御された Push遷移● 1画面から複数の種類の遷移先
NavigationView → NavigationStack の書き換えNavigationView {CourseScreen()}struct CourseScreen: View {...@State var isActive = false@State var selectedTopicID = ""var body: some View {ZStack {NavigationLink(isActive: $isActive) {TopicScreen(topicID: selectedTopicID)} label: {EmptyView()}VStack {ForEach(course.topicIDs, id: \.self) { id inButton("topic id: \(id)") {selectedTopicID = idisActive = true}}}}...}}NavigationStack {CourseScreen()}struct CourseScreen: View {...@State var isActive = false@State var selectedTopicID = ""var body: some View {VStack {ForEach(course.topicIDs, id: \.self) { id inButton("topic id: \(id)") {selectedTopicID = idisActive = true}}}.navigationDestination(isPresented: $isActive) {TopicScreen(topicID: selectedTopicID)}...}}不自然なZStackとNavigationLinkが消えてスッキリ
運用状況
1. Issueを作成し、課題としてチーム内共有する。2. 動作確認の担保、書き換え方針を共有する。3. 品質改善の時間で実際にコードの書き換えを行う。計画
● 課題をオープンにすることで、以下のメリットを受けています。○ 目につくので忘れない○ いつでも見返せる○ 対応時期のコミュニケーションが容易1. Issueを作成し、課題としてチーム内共有する。
● MagicPodを用いたE2Eテストを導入しています。○ 画面遷移などの書き換えも安心して書き換えができます。● 書き換えの方針などを事前共有によってチーム内で検証します。2. 動作確認の担保、書き換え方針を共有する。
私たちのチームでは品質改善に向けた実装時間が確保されています。● Quality Budget○ 2週間に1日品質改善に寄与する issueを消化する日を設けています。● KAIZEN○ 小中高プロダクトiOSチームでプロダクトを跨いでペアを組み、週に1回1時間程度品質改善に当てる。3. 品質改善の時間で実際にコードの書き換えを行う。
● 『スタディサプリ』は年に1回バージョン更新を行なっています。○ 今年の4月にiOS 14をサポートバージョンから外しました。○ シェア率を参照しながらPdMとすり合わせを行い更新しています。● これから導入を控えているもの。今後の予定はhttps://developer.apple.com/documentation/swiftui/navigationstackhttps://developer.apple.com/documentation/swiftui/view/presentationdetents(_:)
まとめ04
私たちはSwiftUIの進化を追いながら、落ち着いて取捨選択ができたと思います。書籍「進化的アーキテクチャ」と照らし合わせ要因を振り返りました。要因● 年一回のサポートバージョンの見直しタイミングがある○ 腐敗防止層の対策が立てやすい● モジュール分割により、新しいコードは新しい設計で書くことができる○ 漸進的な改善を行うことができる● メインタスクとは別で品質改善のために取り組む時間がある○ 心理的にも余裕が生まれる運用を通しての振り返り
最後に『スタディサプリ 中学講座』で得たまなび私たちのSwiftUIという選択は、2020年時点では将来性のリスクを取ることだったと思います。導入時点ではどれも予測のつかない変化でしたが、その点で過剰に忌避するのではなく、ワークアラウンドな対応なども受け入れながらSwiftUIの進化に合わせて一緒に進化しつつ、導入タイミングはプロダクトでハンドリングできる基盤を整えておくことの重要性を改めてまなぶことができました。
その他 弊社についてのご紹介以下リンク先でもプロダクト開発部について紹介しています。ぜひご覧ください。・スタディサプリ プロダクトチーム ブログ スタディサプリ Product Team Blog 発表資料 - スタディサプリ Product Team Blog ※エンジニア / デザイナー / TPMが記事を書いています・ブランドサイト スタディサプリ BRAND SITE・採用ページはこちら キャリア | スタディサプリ BRAND SITE・カジュアル面談はこちらからお気軽にご応募ください スタディサプリエンジニア職種カジュアル面談エントリーフォーム
一緒に事業拡大を目指す仲間をお待ちしています!
ご清聴ありがとうございました