Slide 1

Slide 1 text

Swift ConcurrencyʹΑΔ 
 ҆શͰշదͳඇಉظॲཧ Tatsuya Tanaka / ాத ୡ໵ Qiita Night-Swift6͕΋ͨΒ͢։ൃऀମݧΛ༧ଌ͠Α͏ʂ (#QiitaNight)

Slide 2

Slide 2 text

ͨͳͨͭ / Tatsuya Tanaka • Ϡϑʔגࣜձࣾ / iOSΞϓϦࠇଳ • TechFeed Expert @tattn @tanakasan2525 @tattn

Slide 3

Slide 3 text

VTuberελΠϧͰWebձٞʹࢀՃͰ͖ΔΞϓϦެ։த

Slide 4

Slide 4 text

WWDC Extended Tokyo 2022։࠵ IUUQTZKNFFUVQDPOOQBTTDPNFWFOU

Slide 5

Slide 5 text

IUUQTJODSFNFOUTDPOOQBTTDPNFWFOU

Slide 6

Slide 6 text

Swift 6Ͱඇಉظॲཧ͸ 
 ͞Βʹ γϯϓϧ Ͱ ؆୯ 
 ʹͳΔ

Slide 7

Slide 7 text

ඇಉظॲཧͷ೉͍͠ͱ͜Ζ

Slide 8

Slide 8 text

Մಡੑͷҡ࣋ ഉଞ੍ޚ

Slide 9

Slide 9 text

Մಡੑͷҡ࣋ ഉଞ੍ޚ

Slide 10

Slide 10 text

Completion HandlerͷՄಡੑ func configureApp() { let group = DispatchGroup() (0...2).forEach { _ in group.enter() } // アプリの更新チェック var updateInfo: UpdateInfo! forcedUpdate.checkUpdates { updateInfo = $0 group.leave() } // データマイグレーション dataMigrator.migration { // データマイグレーションの結果を保存 saveMigrationResult($0) group.leave() } var weather: Weather! // 現在地を取得 locationAPI.getLocation { // 現在地の天気を取得 weatherAPI.request(location) { weather = $0 group.leave() } } group.notify(queue: .main) { guard !updateInfo.isUpdateRequired else { // アプリのアップデートを促す } // UIにデータを反映 } } ࿈ଓͨ͠ඇಉظॲཧͷՄಡੑ͕௿͍ (ίʔυͷॲཧॱ্͕͔ΒԼʹྲྀΕ͍ͯͳ͍) ΞϓϦͷߋ৽νΣοΫ σʔλϚΠάϨʔγϣϯ ݱࡏ஍औಘ ݱࡏ஍ͷఱؾΛऔಘ ϚΠάϨʔγϣϯ݁ՌΛอଘ UIʹ൓ө ߋ৽͕͋Ε͹ΞϥʔτΛग़͢

Slide 11

Slide 11 text

ϦΞΫςΟϒϑϨʔϜϫʔΫͷՄಡੑ func configureApp() { Publishers.Zip3( // アプリの更新チェック forcedUpdate.checkUpdates(), // データマイグレーション dataMigrator.migration().map(saveMigrationResult), // 現在地の天気を取得 locationAPI.getLocation().map(weatherAPI.request) ) .sink { (updateInfo, _, weather) in guard !updateInfo.isUpdateRequired else { // アプリのアップデートを促す } // UIにデータを反映 } .store(in: &cancellables) } ίʔυྔ͸ݮΔ͕ɺ ΞϓϦͷߋ৽νΣοΫ σʔλϚΠάϨʔγϣϯ ݱࡏ஍औಘ ݱࡏ஍ͷఱؾΛऔಘ UIʹ൓ө ϚΠάϨʔγϣϯ݁ՌΛอଘ ߋ৽͕͋Ε͹ΞϥʔτΛग़͢ ɾΦϖϨʔλ౳ͷཧղ͕ඞཁ ɾσόοάͷ೉қ౓্͕͕Δ ɾετϦʔϜ͕௕͘ͳΔͱՄಡੑ͕େ͖͘མͪΔ (ϦΞΫςΟϒͰ͸ͳ͍γϯϓϧͳඇಉظॲཧʹ͸ෳࡶ)

Slide 12

Slide 12 text

Swift Concurrency Swift 5ܥ

Slide 13

Slide 13 text

async/await func configureApp() async throws { // アプリの更新チェック async let updateInfo = forcedUpdate.checkUpdates() // データマイグレーション async let migrationResult = dataMigrator.migration() // 現在地の天気を取得 async let weather = try weatherAPI.request( locationAPI.getLocation() ) // データマイグレーションの結果を保存 await saveMigrationResult(migrationResult) guard await !updateInfo.isUpdateRequired else { // アプリのアップデートを促す } // UIにデータを反映 } ಉظॲཧͷΑ͏ͳݟͨ໨ͷίʔυʹͳΓ 
 ϑϩʔΛ௥͍΍͍͢ ΞϓϦͷߋ৽νΣοΫ σʔλϚΠάϨʔγϣϯ ݱࡏ஍औಘ ݱࡏ஍ͷఱؾΛऔಘ UIʹ൓ө ϚΠάϨʔγϣϯ݁ՌΛอଘ ߋ৽͕͋Ε͹ΞϥʔτΛग़͢

Slide 14

Slide 14 text

Մಡੑͷҡ࣋ ഉଞ੍ޚ

Slide 15

Slide 15 text

ഉଞ੍ޚ΁ͷߴ͍ҙࣝ εϨουηʔϑͰ͸ͳ͍ૢ࡞Λ͢Δ࣌͸ data race͕ൃੜ͠ͳ͍Α͏ʹҙ࣮ࣝͯ͠૷͢Δ let queue = DispatchQueue(label: "sample.code.qiitanight") var landmarksInRegion: [Region: [Landmark]] = [:] /// 現在地の区画が更新された時に呼ばれる /// - Parameter region: 現在地が含まれる区画 func onUpdateRegion(_ region: Region) { // 周辺のランドマーク検索 searchLandmarks(in: region) { [weak self] landmarks in queue.async { self?.landmarksInRegion[region] = landmarks } } }

Slide 16

Slide 16 text

Swift Concurrency Swift 5ܥ

Slide 17

Slide 17 text

Actor @globalActor struct LocationActor { actor ActorType {} static let shared = ActorType() } @LocationActor var landmarksInRegion: [Region: [Landmark]] = [:] /// 現在地の区画が更新された時に呼ばれる /// - Parameter region: 現在地が含まれる区画 func onUpdateRegion(_ region: Region) async { // 周辺のランドマーク検索 let landmarks = await searchLandmarks(in: region) landmarksInRegion[region] = landmarks } ActorΛ࢖͏ͱσʔλڝ߹ՕॴΛϏϧυΤϥʔʹͰ͖Δ

Slide 18

Slide 18 text

Actor @globalActor struct LocationActor { actor ActorType {} static let shared = ActorType() } @LocationActor var landmarksInRegion: [Region: [Landmark]] = [:] /// 現在地の区画が更新された時に呼ばれる /// - Parameter region: 現在地が含まれる区画 @LocationActor func onUpdateRegion(_ region: Region) async { // 周辺のランドマーク検索 let landmarks = await searchLandmarks(in: region) landmarksInRegion[region] = landmarks } SwiftίϯύΠϥʹνΣοΫΛ೚ͤΔ͜ͱͰ 
 ࣮૷࣌ʹߟ͑Δ͜ͱ΍ɺίʔυϨϏϡʔͷෛ୲΋ݮΒͤΔ

Slide 19

Slide 19 text

Swift 5ܥͷSwift Concurrency ɾॲཧϑϩʔ͕෼͔Γ΍͍͢ ɾഉଞ੍ޚ͕ඞཁͳΒActorΛ࢖͑͹ྑ͍ ؆୯ γϯϓϧ ɾഉଞ੍ޚ͕ඞཁͳ෦෼ΛίϯύΠϥ͕ڭ͑ͯ͘ΕΔ

Slide 20

Slide 20 text

Swift Concurrency Swift 6

Slide 21

Slide 21 text

func run() { let ref = ReferenceValue() Task { ref.value += 1 } } final class ReferenceValue { var value = 1 } σʔλڝ߹νΣοΫͷݫີԽ Swift 5ܥͰ͸ແܯࠂɺSwift 6Ͱ͸Τϥʔ ❌ কདྷతʹσʔλڝ߹͕ى͜ΔՄೳੑ

Slide 22

Slide 22 text

Swift 6ͰϏϧυΤϥʔʹͳΔՕॴΛࣄલʹௐ΂Δ let package = Package( ... ) package.targets.forEach { $0.swiftSettings = [.unsafeFlags(["-Xfrontend", "-warn-concurrency", "-Xfrontend", "-enable-actor-data-race-checks"])] } OTHER_SWIFT_FLAGS = -Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks Swift 5ܥͰ΋Swift 6ͰΤϥʔʹͳΔՕॴΛܯࠂʹͰ͖Δ SwiftPMͷ৔߹ XcodeͰઃఆ͢Δ৔߹

Slide 23

Slide 23 text

Swift 5Ͱ΋ܯࠂʹͰ͖Δ func run() { let ref = ReferenceValue() Task { ref.value += 1 } } final class ReferenceValue { var value = 1 }

Slide 24

Slide 24 text

UIKitͷMainActorνΣοΫ΋༗ޮʹͳΔ func updateUI() { let bounds = UIScreen.main.bounds // ϨΠΞ΢τܭࢉ } @MainActor(unsafe) ͷνΣοΫ΋༗ޮʹͳΔͨΊ UIKitΛ࢖͍ͬͯΔ৔߹͸େม͔΋… কདྷతʹ͸@preconcurrencyͳͲͰஈ֊Ҡߦ͠΍͘͢ͳΔʁ

Slide 25

Slide 25 text

Swift 6Ͱى͜ΔมԽ (Swift Concurrency) • ୭Ͱ΋ڧ੍తʹ҆શͳඇಉظίʔυʹಋ͔ΕΔ • ίʔυϨϏϡʔ΍σόοάͷίετΛݮΒͤΔ • αʔυύʔςΟ΍ΞϓϦ಺ͷίʔυͷasync/awaitԽ͕ਐΉ Swift 6Ͱඇಉظॲཧ͸ 
 ͞Βʹ γϯϓϧ Ͱ ؆୯ 
 ʹͳΔ

Slide 26

Slide 26 text

ࢀߟࢿྉ ɾOn the road to Swift 6 ɹɾhttps://forums.swift.org/t/on-the-road-to-swift-6/32862 ɾIncremental migration to concurrency checking 
 ɹɾhttps://github.com/apple/swift-evolution/blob/main/proposals/0337-support-incremental-migration-to-concurrency-checking.md ɾPiecemeal adoption of Swift 6 improvements in Swift 5.x 
 ɹɾhttps://forums.swift.org/t/piecemeal-adoption-of-swift-6-improvements-in-swift-5-x/57184 ɾSendable and @Sendable closures ɹɾhttps://github.com/apple/swift-evolution/blob/main/proposals/0302-concurrent-value-and-concurrent-closures.md