Slide 1

Slide 1 text

iOS18 から追加された SwiftUI の傾向について 調べてみる Mobile勉強会 ウォンテッドリー × チームラボ × Sansan #17 @swiftty

Slide 2

Slide 2 text

自己紹介 林達也 ウォンテッドリー株式会社  swiftty  _swiftty 性格診断 - ハーモナイザー(サポート系統)

Slide 3

Slide 3 text

今日話すこと iOS 18 で追加された API 一覧について切り口を変えて調べてみた話 どうやって調べてみたか 調べた結果どういった傾向があったか (先に話してしまうと意外な発見みたいなものはありませんでした。 。 。 )

Slide 4

Slide 4 text

きっかけ

Slide 5

Slide 5 text

Apple Developer Apple Document でどういった API 差分があるか見ることができる ただし最新の Xcode がパブリックリリースされると、その前のメジャーバージョンと の比較ができなくなる そこでモジュール定義から差分を取り出せるのではと思い試してみた

Slide 6

Slide 6 text

モジュール定義の場所 システムライブラリは以下のパスに存在する Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPh oneOS.sdk/System/Library/Frameworks/ SwiftUI は以下が関連しそう SwiftUI.framework/*.swiftinterface SwiftUICore.framework/*.swiftinterface

Slide 7

Slide 7 text

swiftinterface とは Swift はヘッダファイルは .h などではなく、 .swiftinterface というファイルにパブリッ クな API が宣言されている 中身は定義ジャンプで見るときと同じような形式の Swift 表現 ※ 定義ジャンプでは表示されないパブリックな定義も含めて見ることができる ... @available(iOS 18.0, macOS 15.0, tvOS 18.0, watchOS 11.0, visionOS 2.0, *)   public struct ScrollPhaseChangeContext { public var geometry: SwiftUICore.ScrollGeometry { get } public var velocity: CoreFoundation.CGVector? { get } } ...

Slide 8

Slide 8 text

どのように一覧を取り出すか? swiftinterface は SwiftSyntax で valid なファイルとして扱える @available(iOS 18.0) を検知すれば取り出せそう

Slide 9

Slide 9 text

SyntaxRewriter SyntaxRewriter を用いて実装 ~DeclSyntax の attributes に @available 定義が格納されている node.attributes の中から AvailabilityArgumentListSyntax のものを探索し platform と version を判定 final class AvailableIOS18Rewriter: SyntaxRewriter { override func visit(_ node: StructDeclSyntax) -> DeclSyntax { ... } private func checkAvailableForIOS18(_ arguments: AvailabilityArgumentListSyntax) -> Bool { return arguments.contains(where: { argument in switch argument.argument { case .availabilityVersionRestriction(let version): return version.platform.trimmed.text == "iOS" && version.version?.major.trimmed.text == "18"   default: return false } }) }

Slide 10

Slide 10 text

SyntaxRewriter SyntaxRewriter を用いて実装 @available(iOS 18.x) が見つからなければ MissingDeclSyntax を返し、 iOS 18 ではない定義を空文字で書き換える final class AvailableIOS18Rewriter: SyntaxRewriter { override func visit(_ node: StructDeclSyntax) -> DeclSyntax {   let hasAvailable = checkAvailableForIOS18(...) if hasAvailable { return super.visit(node) } else { return DeclSyntax(MissingDeclSyntax(placeholder: "")) } }

Slide 11

Slide 11 text

結果 https://gist.github.com/swiftty/f4e9a67ef704cd2781e9701a9b644150

Slide 12

Slide 12 text

傾向 extension など同じような定義を除いて 180 ほどの新規の定義が存在 その API 一覧を独自に大まかに分類 割合として多いものは以下の傾向となった 関連する型が多いとその分、分類としてカウントする定義が多くなるため上位の実態は同程度の変更量 e.g.) Tab, TabContent, TabPlacement, TabContentBuilder, ...

Slide 13

Slide 13 text

傾向 Tab 関連 .tabItem {} が非推奨になり別コンポーネントが追加された TabView { Tab("Home", systemImage: "home") {       HomeView() } } Scroll 関連 .scrollPosition() や .onScrollVisibilityChange() などスクロールされる要素の制御の強 化

Slide 14

Slide 14 text

まとめ 切り口を変えて調べてみるという取り組みは達成できた iOS 18 においては _printChanges などのような新しい発見はなかった。 。 。 SwiftSyntax のちょっと変わった使い方の紹介 Tab のデータ構造が変わった影響で関連 API の追加が目立っている Scroll や Accessibility の機能追加も継続的に進められている

Slide 15

Slide 15 text

ご清聴ありがとうございました

Slide 16

Slide 16 text

付録 private func checkAvailableForIOS18(_ attributes: AttributeListSyntax) -> Bool? { func checkArguments(_ arguments: AvailabilityArgumentListSyntax) -> Bool { arguments.contains(where: { argument in switch argument.argument { case .availabilityVersionRestriction(let version): return version.platform.trimmed.text == "iOS" && version.version?.major.trimmed.text == "18" default: return false } }) } let attributes = attributes.compactMap { attribute in switch attribute { case .attribute(let attr): return attr.arguments?.as(AvailabilityArgumentListSyntax.self) default: return nil } } if attributes.isEmpty { return nil } return attributes.contains(where: { attribute in checkArguments(attribute) }) }