Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
メインスレッドをブロックさせないためのSwift Concurrencyクイズ
Search
tokizo
August 23, 2024
5.9k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
メインスレッドをブロックさせないためのSwift Concurrencyクイズ
tokizo
August 23, 2024
More Decks by tokizo
See All by tokizo
徐々に増えているSwiftUI Anchor関連API
tokizuoh
1
1.1k
iOS 曜日ランキングが出来上がるまで
tokizuoh
0
2.7k
運動モチベーション継続のためのiOSアプリ開発
tokizuoh
0
1.1k
Xcode 15 で swift run が遅い
tokizuoh
0
3.8k
モノレポにおける path-filtering利用時でも GitHub ステータスのRequiredを 機能させたい!
tokizuoh
1
1.6k
累積和で配列の処理効率を改善しよう
tokizuoh
0
740
Featured
See All Featured
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
650
Faster Mobile Websites
deanohume
310
32k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
350
Thoughts on Productivity
jonyablonski
76
5.2k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.9k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
230
23k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
240
How to Ace a Technical Interview
jacobian
281
24k
Mobile First: as difficult as doing things right
swwweet
225
10k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.8k
Transcript
メインスレッドをブロック させないための Swift Concurrency クイズ tokizo / @tokizuoh 2024/08/23 iOSDC
Japan 2024 1
README • tokizo ◦ @tokizuoh • 株式会社はてな ◦ マンガアプリチーム 2
3 メインスレッドをブロック させないための Swift Concurrency クイズ
4 メインスレッドをブロック させないための Swift Concurrency クイズ
5 メインスレッドを 適切に使う
メインスレッドを適切に使う (1/2) • 適切さ ◦ メインスレッドで実行が求められる処理のみを メインスレッドで実行する ▪ UIの更新など ◦
メインスレッドでやらなくて良い処理を バックグラウンドスレッドに逃がす 6
メインスレッドを適切に使う (2/2) • 適切に使わないと... ◦ UIの応答性の低下 ◦ クラッシュ ▪ ユーザー体験の低下
▪ → ユーザー離脱・売上減少 ▪ → ブランドイメージの低下 7
8 メインスレッドを適切に使っ てアプリの品質を高めたい
9 しかし Swift Concurrencyは 難しい
10 Swift Concurrencyの 難しさとは
11 Swift Concurrencyは 規則が多い
Swift Concurrencyは規則が多い (1/2) • Actor, Global Actorなどの詳細な規則を知るには 以下を読む・追う必要がある ▪ Swift
Evolutionのプロポーザル ▪ WWDCのセッション ▪ https://developer.apple.com/documentation/ swift/concurrency/ 12
Swift Concurrencyは規則が多い (2/2) • 追う必要性 ◦ Swift のバージョンによって規則が変わる 13
14 完全に理解するのは大変
15 規則を理解していないと 意図せず メインスレッドを 使ってしまう
16 今回のトークの クイズを解いて 規則を知ろう
17 トークのゴール
トークのゴール (初級者) • クイズを解くことで、メインスレッドを ブロックさせないために必要な規則や ドキュメントのありかを知ること ◦ 頭の中にインデックスを貼る 18
トークのゴール (熟練者) • 理解度の確認ができること 19
20 ソースコードの共有
ソースコードの共有 • コードのみ(答え無し・解説無し) ◦ https://tokizuoh.hatenablog.com/iosdc-japan-2024-quiz 21
22 クイズのルール
クイズのルール (1/2) • Xcode 15.4 ◦ Swift 5.10 23
クイズのルール (2/2) // ✅: 通る → MainActor上、つまりメインスレッドで実行される* // ❌: 通らない
→ MainActor上で実行されない MainActor.assertIsolated() 24 *: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md
25 練習
import UIKit class PracticeViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad() MainActor.assertIsolated() // ✅ or ❌ ? } } 26
27 答え
import UIKit class PracticeViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad() MainActor.assertIsolated() // ✅ } } 28
29 解説
練習: 解説 (1/3) • UIViewController には @MainActor が付いている 30 https://developer.apple.com/documentation/uikit/uiviewcontroller
練習: 解説 (2/3) 31 *: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md#using-global-actors-on-a-type **: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md#global-actor-inference • クラスに
@MainActor を付けた場合、メソッド、 プロパティ、サブスクリプトは MainActor に 隔離される* • サブクラスはスーパークラスから Actor の隔離を 推論される**
練習: 解説 (3/3) • よって、viewDidLoad() は MainActor 上で実行 される ◦
→ メインスレッドで実行される 32
import UIKit class PracticeViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad() MainActor.assertIsolated() // ✅ } } 33
34 正解の方
35 練習おわり
36 全5問
37 参ります
38 問1
import UIKit class Q1ViewController: UIViewController { override func viewDidLoad() {
super.viewDidLoad() Task.detached { MainActor.assertIsolated() // ✅ or ❌ ? } } } 39
40 答え
41 import UIKit class Q1ViewController: UIViewController { override func viewDidLoad()
{ super.viewDidLoad() Task.detached { MainActor.assertIsolated() // ❌ } } }
42 解説
問1: 解説 • Detached Task は呼び出し側の Actor の 一部ではない、非同期に実行できる作業単位* ◦
→ MainActor とは別で実行されるため、 メインスレッドで実行されない 43 *: https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/#Unstructured-Concurrency
44 import UIKit class Q1ViewController: UIViewController { override func viewDidLoad()
{ super.viewDidLoad() Task.detached { MainActor.assertIsolated() // ❌ } } }
45 正解の方🙋
import UIKit // 以後省略 class Q1ViewController: UIViewController { override func
viewDidLoad() { super.viewDidLoad() Task.detached { MainActor.assertIsolated() // ❌ } } } 46
47 問2
func foo() async { MainActor.assertIsolated() // ✅ or ❌ ?
} class Q2ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { @MainActor in await foo() } } } 48
49 答え
func foo() async { MainActor.assertIsolated() // ❌ } class Q2ViewController:
UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { @MainActor in await foo() } } } 50
51 解説
問2: 解説 (1/3) • in の前に @MainActor を付けると、 クロージャの処理が Main
Actor で実行される* 52 https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md#closures
問2: 解説 (2/3) • await foo() は MainActor 上で呼び出される •
しかし、foo() 自体はどの Actor にも 隔離されていない async function のため、 中身の処理は MainActor 上で実行されない* 53 *: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0338-clarify-execution-non-actor-async.md#detailed-design
@MainActor func foo() async { MainActor.assertIsolated() // ✅ } •
関数に @MainActor を付けると通る 問2: 解説 (3/3) 54
func foo() async { MainActor.assertIsolated() // ❌ } class Q2ViewController:
UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { @MainActor in await foo() } } } 55
56 正解の方
57 問3
@propertyWrapper struct AlwaysZero { @MainActor var wrappedValue: Int { return
0 } } struct Counter { @AlwaysZero var value: Int func f() { MainActor.assertIsolated() /* ✅ or ❌ ? */ } } class Q3ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { await Counter().f() } } } 58
59 答え
@propertyWrapper struct AlwaysZero { @MainActor var wrappedValue: Int { return
0 } } struct Counter { @AlwaysZero var value: Int func f() { MainActor.assertIsolated() /* ✅ */ } } class Q3ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { await Counter().f() } } } 60
61 解説
問3: 解説 (1/3) • Global Actor が付与された wrappedValue を持つ プロパティラッパーが付与されたプロパティを持つ
構造体やクラスはそのプロパティラッパーから Actor の隔離が推論される* 62 *: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md#global-actor-inference
問3: 解説 (2/3) • → @AlwaysZero が付与されたプロパティを持つ Counter は MainActor
に隔離される 63 @propertyWrapper struct AlwaysZero { @MainActor var wrappedValue: Int { return 0 } } struct Counter { @AlwaysZero var value: Int func f() { MainActor.assertIsolated() /* ✅ */ } }
問3: 解説 (3/3) • Swift 6からは無効になる* ◦ Swift 5.9以降 Upcoming
Feature Flag が使える ▪ DisableOutwardActorInference 64 *: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0401-remove-property-wrapper-isolation.md
@propertyWrapper struct AlwaysZero { @MainActor var wrappedValue: Int { return
0 } } struct Counter { @AlwaysZero var value: Int func f() { MainActor.assertIsolated() /* ✅ */ } } class Q3ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { await Counter().f() } } } 65
66 正解の方🙋
67 問4
@MainActor class Animal { deinit { MainActor.assertIsolated() // ✅ or
❌ ? } } class Q4ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { await Animal() } } } 68
69 答え
@MainActor class Animal { deinit { MainActor.assertIsolated() // ❌ }
} class Q4ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { await Animal() } } } 70
71 解説
問4: 解説 • deinit は Global Actor に隔離されない* • 2024/08/21現在、isolated
deinit の プロポーザル** が Accept されている*** 72 *: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md#detailed-design **: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0371-isolated-synchronous-deinit.md ***: https://forums.swift.org/t/accepted-with-modifications-se-0371-isolated-synchronous-deinit/74042
@MainActor class Animal { deinit { MainActor.assertIsolated() // ❌ }
} class Q4ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { await Animal() } } } 73
74 正解の方
75 問5
protocol P { @MainActor func f() } struct Y: P
{} extension Y { func f() { MainActor.assertIsolated() /* ✅ or ❌ ? */ } } class Q5ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { Y().f() } } } 76
77 答え
protocol P { @MainActor func f() } struct Y: P
{} extension Y { func f() { MainActor.assertIsolated() /* ❌ */ } } class Q5ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { Y().f() } } } 78
79 解説
問5: 解説 (1/3) • SE-0316* 内のコードをほぼそのまま使用 • プロトコルの実装を準拠とは別に extension で
行うと、そのプロトコルが要求する Global Actor を 引き継がない 80 *: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md#global-actor-inference
問5: 解説 (2/3) 81 https://github.com/swiftlang/swift-evolution/blob/main/proposals/0316-global-actors.md#global-actor-inference
• 問5のコードをよく見ると、await が無いので 同期メソッドを呼んでいるだけ class Q5ViewController: UIViewController { override func
viewDidLoad() { super.viewDidLoad() Task.detached { Y().f() } } } 問5: 解説 (3/3) 82
protocol P { @MainActor func f() } struct Y: P
{} extension Y { func f() { MainActor.assertIsolated() /* ❌ */ } } class Q5ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() Task.detached { Y().f() } } } 83
84 正解の方🙋
85 全5問 ありがとうございました!
クイズ まとめ • 問1: SE-0304 Detached Task • 問2: SE-0338
Actor 隔離されていない非同期関数 • 問3: SE-0401 プロパティラッパーからの推論 • 問4: SE-0316 Global Actorの規則 • 問5: SE-0316 Global Actorの規則 86
87 何問解けましたか?
88 全問正解の方 🙋
89 拍手👏
90 メインスレッドを 適切に 使っていきましょう!