Share
Embed
モジュールの視点からSwiftを読み解く #iosdc
Shigure Shimotori
September 13, 2026
Transcript
90 slides
-
本日のコンテンツ モジュール @unknown default 暗黙の Sendable 最適化と @inlinable と @usableFromInline
「import して使える」 とは swiftinterface について詳しく 4 -
本日のコンテンツ モジュール @unknown default 暗黙の Sendable 最適化と @inlinable と @usableFromInline
「import して使える」 とは swiftinterface について詳しく 5 -
Swift におけるモジュール モジュールは、 コード配布の単位で、 単体で構築および配布され、 import キーワードを使用して別のモジュールによってインポートできる フレームワークまたはアプリケーションです。 by TSPL日本語版
import xxx の xxx に書けるものがモジュール。 たとえば: Xcode上で見かけるフレームワーク、アプリケーション Package.swift に書いた targets: [...]たち 7 -
よく聞くワード:マルチモジュール構成 1つのアプリを作るために、複数のモジュールへ小分けにして開発する モジュールごとに違う設定を入れて徐々にConcurrency対応する + モジュールごとにキャッシュを効かせてビルド速度を速くする それぞれのモジュールを別々に扱う、 異なるタイミングでコンパイルする 責務ごとにモジュールを分けたうえで疎結合にする open/public な
API はきちんと設計する マルチモジュール構成が知りたい人はこちらへ: iOSDC Japan 2021 大規模なアプリのマルチモジュール構成の実践 by ぎぎにゃんさん iOSDC Japan 2026 巨大モノリシックアプリ モダ ン化大作戦 by Ryomm さん 8 -
本日のコンテンツ モジュール @unknown default 暗黙の Sendable 最適化と @inlinable と @usableFromInline
「import して使える」 とは swiftinterface について詳しく 10 -
UNAuthorizationStatus import UserNotifications // UserNotificationsモジュールを使用 let settings = await UNUserNotificationCenter
.current().notificationSettings() switch settings.authorizationStatus { case .notDetermined: /* すきなように */ case .denied: /* 結果に応じた */ case .authorized: /* 処理を */ case .provisional: /* 書こう */ case .ephemeral: /* !!! */ } 12 -
なんかエラー出た ※Swift 6 言語モードの場合 error: switch covers known cases, but
'UNAuthorizationStatus' may have additional unknown values, possibly added in future versions note: handle unknown values using "@unknown default" 意訳 将来追加される未知の値に対応できてないからエラーにするよ。 @unknown defaultで対応しよう! 13 -
言われるがままに修正する import UserNotifications // UserNotificationsモジュールを使用 let settings = await UNUserNotificationCenter
.current().notificationSettings() switch settings.authorizationStatus { case .notDetermined: /* ... */ case .denied: /* ... */ case .authorized: /* ... */ case .provisional: /* ... */ case .ephemeral: /* ... */ + @unknown default: /* 言われるがままにこれを書き足す…… */ } 14 -
なぜ"possibly added in future versions"と言われるか 新しく追加されたUNAuthorizationStatusの値が 古いアプリに渡されるケース UNAuthorizationStatusの事例: iOS 14
で新しいステータス 「case ephemeral」 が増えた! 16 -
毎夏の恒例行事 iOS 14 へのアップデート前 OS 同梱の UserNotifications iOS 13 までを想定して作ったアプリ
// iOS 13 import UserNotifications enum UNAuthorizationStatus { case notDetermined case denied case authorized case provisional switch settings.authorizationStatus { case .notDetermined: /* ... */ case .denied: /* ... */ case .authorized: /* ... */ case .provisional: /* ... */ } } 17 -
毎夏の恒例行事 iOS 14 へのアップデート完了! OS 同梱の UserNotifications // iOS 14
enum UNAuthorizationStatus { case notDetermined case denied case authorized case provisional + case ephemeral } iOS 13 までを想定して作ったアプリ import UserNotifications switch settings.authorizationStatus { case .notDetermined: /* ... */ case .denied: /* ... */ case .authorized: /* ... */ case .provisional: /* ... */ } 17 -
依存モジュールとアプリの間に情報格差があるかも iOS 14が入ってるiPhone: iOS 14 に App Clip が導入された ユーザの選択次第でステータスが.ephemeral
になる可能性がある。 iOS 13で作ったアプリ: まだ iOS 14 対応していない or アップデートやめた case ephemeral のことは全く知らない。 switch 文にも書いてない。 18 -
.ephemeral はどこに行けばいいんだ??? iOS 14 対応が済んでないアプリには case ephemeral がない import UserNotifications
switch authorizationStatus { case .notDetermined: /* ... */ case .denied: /* ... */ case .authorized: /* ... */ case .provisional: /* ... */ } Objective-C の enum なのでクラッシュ。 19 -
@unknown defaultがあれば安心! 未知の値が来ても対処できる! import UserNotifications switch authorizationStatus { case .notDetermined:
/* ... */ case .denied: /* ... */ case .authorized: /* ... */ case .provisional: /* ... */ + @unknown default: /* ephemeralを受け取ってごまかす! */ } 20 -
補足:実際のところ .ephemeral のせいで意図しない動作をすることはない iOS 13 以前のアプリには App Clip が存在しないのでこいつも飛んでこない 同じ理屈で、
Apple Glass 仮 ができて UIUserInterfaceIdiom に 新しいものが増えても既存のアプリに影響はないはず きっと互換モードで動いて既存の値が渡されるよたぶん 21 -
@unknown default を書かされるとき Objective-C 定義の enum の場合: NS_ENUM を使って定義したもの 大多数の
enum はこれ! Swift 定義の enum の場合: Library Evolution モードを有効にすれば出る SwiftUI は Swift 実装かつ Library Evolution 有効 他にも C 言語の場合とか SE-0487 とかある 22 -
Library Evolution とは モジュールの作者がモジュールに対して設定できるモード あとから新バージョンに差しかわる前提で話を進めるようになる これがあれば SwiftUI だけを iOS 27
にアップデートしても安心! 具体的な効果 あとから差しかえる前提でモジュールが生成され、 動作する あとからアップデートされる前提での利用をアプリ側にうながす 例:@unknown default で未知の値を処理するよう強制する 23 -
SE-0192 と SE-0260 と SE-0487 の違い SE-0192 Handling Future Enum
Cases (Swift 5.0) このころはまだfrozenの設定手段が限定的だったみたい SE-0260 (Swift 5.1) Library Evolution有効時に出まくるようになった 目的はバイナリ互換性 SE-0487 Nonexhaustive enums (Swift 6.3.2) @nonexhaustive の導入 目的はソース互換性 25 -
本日のコンテンツ モジュール @unknown default 暗黙の Sendable 最適化と @inlinable と @usableFromInline
「import して使える」 とは swiftinterface について詳しく 29 -
Swift Concurrency の問題です! 非隔離の struct が Sendable って書かなくても勝手に Sendable になるときって
どんなとき? 答え: その struct が internal 以下で、 プロパティも Sendable なとき! 32 -
正確な答え プロパティが Sendable かつ、 勝手にSendableにしても他のモジュールに直接の影響がないもの 他のモジュールから import して使う struct を
Sendable にするかどうかは 自分で責任もって判断しましょう。 33 -
あとから非 Sendable になっちゃうとめんどい! Sendable として運用するつもりのなかった struct かも あとからうっかり非 Sendable プロパティを足しちゃうかも……
public struct MyStructure { + var value: NonSendableValue } var s = MyStructure() await doOnAnotherActor(s) s.doSomething() error: sending 's' risks causing data races [#SendingRisksDataRace] 34 -
あとからプロパティが増えないとわかっている struct なら… あとから stored property プロパティが増えないなら、 あとから非 Sendable にひっくり返されることもない
暗黙的に Sendable にしても import された先で問題を起こさない! 例えば @frozen public struct とか。 35 -
暗黙的な Sendable? いろんな struct 暗黙的に Sendable にしていい? internal 直接の影響はないから OK
public 安易な Sendable 化はリスク高い @frozen public あとから変更しないから迷惑かけない @usableFromInline internal ??? 36 -
本日のコンテンツ モジュール @unknown default 暗黙の Sendable 最適化と @inlinable と @usableFromInline
「import して使える」 とは swiftinterface について詳しく 38 -
実装を公開して最適化に役立ててもらおう! Array や swift-algorithm でよく見られる public struct Container<Value> { private
let value: Value public func calculate() -> Int { value.doSomething() } } 43 -
インライン化 calculate() の呼び出しコストを削減できる が、 中身の value がよそのモジュールに丸見えになっちゃう! let container =
Container(/* ... */) let answer = container.calculate() + container.value.doSomething() 44 -
@inlinable と @usableFromInline の設定例 public struct Container<Value> { @usableFromInline internal
let value: Value @inlinable public func calculate() -> Int { value.doSomething() } } 46 -
暗黙的な Sendable? いろんな struct 他のモジュールに 影響ある? internal ない public ある
@frozen public ない 仕様が変わらない @usableFromInline internal ある インライン化された先で 使われる 暗黙的に Sendable になれる? 47 -
本日のコンテンツ モジュール @unknown default 暗黙の Sendable 最適化と @inlinable と @usableFromInline
「import して使える」 とは swiftinterface について詳しく 50 -
import したモジュールの中の関数を使う 一般的な理解:import をしても internal 以下のものは使えない internal アクセスにより、 エンティティを定義するモジュールの任意のソース ファイル内で使用できますが、
そのモジュールの外部のソースファイルでは使用 できません。 by TSPL 日本語版 実際のところ… @usableFromInline internal のものが最適化の一環で使える @testable import すると internal のものが呼べる、 テストできる 52 -
モジュールの現物を見てみよう! ファイル名 何者? SwiftUI.framework/ 入れ物 SwiftUI.tbd モジュールの核のハリボテ ◯◯.swiftinterface ↑ には
target triple が入る 取扱説明書 兼 カタログ 53 -
import したモジュールの中の struct や関数が使える条件 モジュールの核(SwiftUI.tbd)が、対象を他モジュールから利用可能にしている アクセス修飾子の区別なく、外部から使えるか、使わせないか、ただそれだけ AND "取扱説明書 兼 カタログ"の記載通りの使いかたを守る
アクセス修飾子の制限をかけているのはこちらのファイル 自由に呼べるのは public 以上 @usableFromInline internal を使えるのは最適化のときだけ @testable import が許されているかどうかも書いてある 55 -
余談:SwiftUI は @testable import できない SwiftUI.framework 生成時に Apple がテスト機能を有効化しなかった その結果、
モジュールが @testable import できるように作られない @testable import SwiftUI error: module 'SwiftUI' was not compiled for testing [#ModuleNotTestable] 56 -
本日のコンテンツ モジュール @unknown default 暗黙の Sendable 最適化と @inlinable と @usableFromInline
「import して使える」 とは swiftinterface について詳しく 58 -
2 種類の"取扱説明書 兼 カタログ" . .swiftmodule .swiftinterface 生成方法 デフォルト 要フラグ
形式 バイナリ テキスト 有益な情報の量 たくさん 少ない 互換性 違うコンパイラから読める? のようなエラーが出る error: module compiled with Swift 6.3 cannot be imported by the Swift 6.4 compiler 61 -
public API と private API アクセス制御の話じゃないよ public API アプリ開発で使っていいAPIのこと Document
APIとも呼ばれる private API アクセス制御的にはopenやpublicだが使ってはいけない(使えない)API Appleの人しか使えない、無理やり使ったらリジェクトされちゃうかも!? non-public APIとも呼ばれる 64 -
Swift における private API とは Library Evolution有効時に@_spiで作ることができる裏メニュー 裏メニューは.private.swiftinterfaceというスペシャルなカタログにのみ掲載される @_spi(Internal) public
func doSomething() { /* ... */ } 65 -
厳密には 1+2 種類の"取扱説明書 兼 カタログ" . .swiftmodule .swiftinterface .private.swiftinterface 生成方法
デフォルト 要フラグ さらにもう 1 つフラグ 形式 バイナリ テキスト テキスト 少ない 同じく少ない が、 裏メニュー付き! 有益な情報の量 たくさん 互換性 67 -
.swiftinterface に裏メニューを載せる .swiftinterfaceの内容を書き換える "モジュールの核"側の変更は不要 ゆるめのアクセス修飾子に書き換えたり、 本来private.swiftinterfaceにしかないものを.swiftinterfaceへ書き足したりする - @usableFromInline - internal
func doSomething() -> Swift.String + public func doSomething() -> Swift.String 68 -
参考文献 - モジュール アクセス制御 (Access Control) https://www.swiftlangjp.com/language-guide/access-control.html Introducing Packages https://docs.swift.org/latest/documentation/packagemanagerdocs/introducingpackages/
Target https://developer.apple.com/documentation/packagedescription/target Swift Compiler https://www.swift.org/documentation/swift-compiler/ Whole-Module Optimization in Swift 3 https://www.swift.org/blog/whole-module-optimizations/ 75 -
参考文献 - フレームワークとバンドル What are Frameworks? https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/ Concepts/WhatAreFrameworks.html Placing content
in a bundle https://developer.apple.com/documentation/bundleresources/placing-content-in-a-bundle 76 -
参考文献 - 互換性と安定性 ABI Stability and More https://www.swift.org/blog/abi-stability-and-more/ [SE-0192] Handling
Future Enum Cases https://github.com/swiftlang/swift-evolution/blob/main/proposals/0192-non-exhaustive-enums.md Xcode 14+ creates arm64-apple-ios.abi.json by default https://forums.swift.org/t/xcode-14-creates-arm64-apple-ios-abi-json-by-default/65380/2 77 -
参考文献 - Library Evolution [SE-0260] Library Evolution for Stable ABIs
https://github.com/swiftlang/swift-evolution/blob/main/proposals/0260-library-evolution.md Library Evolution in Swift https://www.swift.org/blog/library-evolution/ Library Evolution Support in Swift ("Resilience") https://github.com/swiftlang/swift/blob/main/docs/LibraryEvolution.rst 78 -
参考文献 - @unknown default と NS_ENUM Grouping Related Objective-C Constants
https://developer.apple.com/documentation/Swift/grouping-related-objective-c-constants Foundation Release Notes https://developer.apple.com/documentation/macos-release-notes/foundation-release-notes SE-0487 Nonexhaustive enums https://github.com/swiftlang/swift-evolution/blob/main/proposals/0487-extensible-enums.md 79 -
参考文献 - 最適化 SE-0193 Cross-module inlining and specialization https://github.com/swiftlang/swift-evolution/blob/main/proposals/0193-cross-module-inliningand-specialization.md Explore
Swift performance https://developer.apple.com/videos/play/wwdc2024/10217/ 属性 (Attributes) https://www.swiftlangjp.com/language-reference/attributes.html swift-algorithms https://github.com/apple/swift-algorithms マクロ (Macros) https://www.swiftlangjp.com/language-guide/macros.html 81 -
参考文献 - import [SE-0409] Access-level modifiers on import declarations https://github.com/swiftlang/swift-evolution/blob/main/proposals/0409-access-levelon-imports.md
[SE-0444] Member import visibility https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-importvisibility.md 82 -
参考文献 - swiftinterface Plan for module stability https://forums.swift.org/t/plan-for-module-stability/14551 what's in
the file of .swiftmodule?how to open it? https://forums.swift.org/t/whats-in-the-file-of-swiftmodule-how-to-open-it/1032/2 Underscored Attributes Reference https://github.com/swiftlang/swift/blob/main/docs/ReferenceGuides/UnderscoredAttributes.md A Swift Guide (WebKit Wiki) https://github.com/WebKit/WebKit/wiki/A-Swift-Guide 83 -
参考文献 - ライブラリ An Apple Library Primer https://developer.apple.com/forums/thread/715385 Missing librairies
in /usr/lib on Big Sur? https://developer.apple.com/forums/thread/655588 Dynamic Library Design Guidelines https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/ DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html 84 -
参考文献 - シンボルと export trie ld64/src/mach_o/ExportsTrie.h https://github.com/apple-oss-distributions/ld64/blob/main/src/mach_o/ExportsTrie.h ld64/src/ld/LinkEdit.hpp https://github.com/apple-oss-distributions/ld64/blob/main/src/ld/LinkEdit.hpp dyld/dyld/Loader.cpp
https://github.com/apple-oss-distributions/dyld/blob/main/dyld/Loader.cpp 85 -
参考文献 - Private API Code Naming Basics https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CodingGuidelines/ Articles/NamingBasics.html Try-Swift-Playgrounds
https://github.com/Private-Playgrounds/Try-Swift-Playgrounds RuntimeViewer https://github.com/MxIris-Reverse-Engineering/RuntimeViewer 86 -
参考文献 - サンプルで使ったもの UNAuthorizationStatus https://developer.apple.com/documentation/usernotifications/unauthorizationstatus UIUserInterfaceIdiom https://developer.apple.com/documentation/uikit/uiuserinterfaceidiom Optional https://developer.apple.com/documentation/swift/optional Enabling
notifications in App Clips https://developer.apple.com/documentation/appclip/enabling-notifications-in-app-clips 87 -
いつもありがとうございます! mtj0928/SlideKit: SwiftUI framework for presentation slides https://github.com/mtj0928/SlideKit SwiftFiddle -
Swift Online Playground https://swiftfiddle.com/ いらすとや https://www.irasutoya.com/ twemoji https://github.com/twitter/twemoji 88