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
TCAでiOS開発を_学ぶ3つの利点.pdf
Search
entaku
November 14, 2023
280
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TCAでiOS開発を_学ぶ3つの利点.pdf
entaku
November 14, 2023
More Decks by entaku
See All by entaku
Swiftでもいろんな文字_の読み上げをしたい__.pdf
entaku
0
120
AVAudioSessionの全体像を掴む.pdf
entaku
0
180
Core_Audio徹底解剖.pdf
entaku
4
440
わたしと今年のSwift.pdf
entaku
1
210
個人開発をTCAで運用していくということ.pdf
entaku
0
80
パッケージ管理でモバイル開発を安全に進める.pdf
entaku
0
1.3k
個人開発をTCAで運用していくということ.pdf
entaku
0
1.5k
技術コミュニティで技術書典出してみた.pdf
entaku
0
130
What_s_new_in_voice_processing他What_s_new_in_Audio.pdf
entaku
1
330
Featured
See All Featured
Paper Plane
katiecoart
PRO
2
52k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.4k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
53k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
1
390
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Optimizing for Happiness
mojombo
378
71k
Everyday Curiosity
cassininazir
0
270
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
990
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
360
Become a Pro
speakerdeck
PRO
31
6.2k
Transcript
TCAͰiOS։ൃΛ ֶͿ3ͭͷར entaku potatotips #85@Voicy
entaku • name: entaku • job: iOSΤϯδχΞͳͲ • SIer6 •
εϙʔπϚονϯάΞϓϦ1 • ྲྀITαʔϏε 2 • Voicy • Twitter • @entaku_0818
γϯϓϧԻͱ͍͏ΞϓϦͰ TCAΛ0.39.1->1.2.0όʔδϣϯΞοϓ https://github.com/entaku0818/VoiceMemo https://apps.apple.com/jp/app/id6443528409
TCAͬͯ·͔͢ʁʁ https://github.com/pointfreeco/swift-composable-architecture
TCAͬͯͲ͏Αʁ ·ͨ5$"͔ʙ ·ͩ5$"ͱ͔Θͳ͍͠ɺαϯϓϧͱ ͔ΈͯͪΐͬͱΘ͔Βͳ͍ͳ Ͳ͏ͤ·ͩۀͰ͑Δ༰ͳΜͯҰ ͭͳ͍ΜͰ͠ΐ͏ʁʁʁ
TCAͬͯͲ͏Αʁ ·ͨ5$"͔ʙ ·ͩ5$"ͱ͔Θͳ͍͠ɺαϯϓϧͱ ͔ΈͯͪΐͬͱΘ͔Βͳ͍ͳ Ͳ͏ͤ·ͩۀͰ͑Δ༰ͳΜͯҰ ͭͳ͍ΜͰ͠ΐ͏ʁʁʁ
͋ͳ͕ͨTCAΛ͏͖ཧ༝ • TCAͰSwiftͷSwift concurrencyͷར༻ྫ͕ݟ ΕΔʂ • TCAͰTCAͷػೳͷɺҰ෦Λ֎෦ϥΠϒϥ Ϧͱͯ͠ར༻͢Δ͜ͱ͕Ͱ͖Δʂ • TCAͰSwift
concurrencyͷ࠷৽ΛΩϟον ΞοϓͰ͖Δʂ
TCAͰSwiftͷSwift concurrencyͷར༻ྫ͕ݟΕΔʂ https://developer.apple.com/documentation/swift/ concurrency
͜Ε·ͰͷԻॲཧ https://developer.apple.com/documentation/swift/ concurrency class ViewController: UIViewController, AVAudioRecorderDelegate { var audioRecorder:
AVAudioRecorder? func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) { if flag { print("Ի͕ਖ਼ৗʹऴྃ͠·ͨ͠ɻ") // Ի͕ޭͨ͠߹ͷॲཧΛ͜͜ʹهड़ } else { print("Ի͕ޭ͠·ͤΜͰͨ͠ɻ") } } func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) { if let error = error { print("ΤϯίʔυதʹΤϥʔ͕ൃੜ͠·ͨ͠: \(error.localizedDescription)") } } }
ԻॲཧͰSwift concurrencyΛར༻ https://developer.apple.com/documentation/swift/ concurrency func start(url: URL) async throws ->
Bool { // ॲཧ͕͍ͷͰ͍ͨ͠෦Ҏ֎লུ self.delegate = Delegate( didFinishRecording: { flag in continuation.yield(flag) continuation.finish() try? AVAudioSession.sharedInstance().setActive(false) }, encodeErrorDidOccur: { error in continuation.finish(throwing: error) try? AVAudioSession.sharedInstance().setActive(false) } ) let stream = AsyncThrowingStream<Bool, Error> { continuation in do { self.recorder = recorder recorder.delegate = self.delegate continuation.onTermination = { [recorder = UncheckedSendable(recorder)] _ in recorder.wrappedValue.stop() } self.recorder?.record() } catch { continuation.finish(throwing: error) } } } } • async/awaitͰԻͷඇಉظॲཧΛ࣮ݱ
ԻॲཧͰSwift concurrencyΛར༻ https://developer.apple.com/documentation/swift/ concurrency case let .recordingMemo(.presented(.delegate(.didFinish(.success(recordingMemo))))): state.recordingMemo = nil
state.voiceMemos.insert( VoiceMemo.State( date: recordingMemo.date, duration: recordingMemo.duration, url: recordingMemo.url ), at: 0 ) return .none • ޭ࣌ͷॲཧͷΈΞϓϦଆʹॻ͚ΔΑ͏ʹͳΔ
TCAͰTCAͷػೳͷɺҰ෦Λ֎෦ϥ ΠϒϥϦͱͯ͠ར༻͢Δ͜ͱ͕Ͱ͖Δʂ https://developer.apple.com/documentation/swift/ concurrency
TCAҎ֎ϥΠϒϥϦͱͯ͠ఏڙ https://developer.apple.com/documentation/swift/ concurrency https://github.com/pointfreeco/swift-dependencies
TCAҎ֎ϥΠϒϥϦͱͯ͠ఏڙ https://developer.apple.com/documentation/swift/ concurrency https://github.com/pointfreeco/swift-dependencies
TCAͰґଘੑͷΈ https://developer.apple.com/documentation/swift/ concurrency https://github.com/pointfreeco/swift-dependencies • live • ओʹ࣮ΞϓϦͰಈ࡞͢Δ • test
• ςετͰಈ࡞͢Δ Dependency • preview • Xcode Previews Ͱಈ࡞͢Δ
ґଘੑͷΈ https://developer.apple.com/documentation/swift/ concurrency extension AudioRecorderClient: DependencyKey { static var liveValue:
Self { let audioRecorder = AudioRecorder() return Self( currentTime: { await audioRecorder.currentTime }, requestRecordPermission: { await AudioRecorder.requestPermission() }, startRecording: { url in try await audioRecorder.start(url: url) }, stopRecording: { await audioRecorder.stop() } ) } } https://github.com/pointfreeco/swift-dependencies
ґଘੑͷΈ https://developer.apple.com/documentation/swift/ concurrency https://github.com/pointfreeco/swift-dependencies extension AudioRecorderClient: TestDependencyKey { static var
previewValue: Self { let isRecording = ActorIsolated(false) let currentTime = ActorIsolated(0.0) return Self( currentTime: { await currentTime.value }, requestRecordPermission: { true }, startRecording: { _ in await isRecording.setValue(true) while await isRecording.value { try await Task.sleep(for: .seconds(1)) await currentTime.withValue { $0 += 1 } } return true }, stopRecording: { await isRecording.setValue(false) await currentTime.setValue(0) } ) } static let testValue = Self( currentTime: unimplemented("\(Self.self).currentTime", placeholder: nil), requestRecordPermission: unimplemented( "\(Self.self).requestRecordPermission", placeholder: false ), startRecording: unimplemented("\(Self.self).startRecording", placeholder: false), stopRecording: unimplemented("\(Self.self).stopRecording") ) }
TCAͰSwift concurrencyͷ ࠷৽ΛΩϟονΞοϓͰ͖Δʂ https://developer.apple.com/documentation/swift/ concurrency
clockͷར༻ https://developer.apple.com/documentation/swift/ concurrency @Dependency(\.continuousClock) var clock case .onTask: return .run
{ [url = state.url] send in async let startRecording: Void = send( .audioRecorderDidFinish( TaskResult { try await self.audioRecorder.startRecording(url) } ) ) for await _ in self.clock.timer(interval: .seconds(1)) { await send(.timerUpdated) } await startRecording } • Ի࣌ͷλΠϚʔॲཧ
clockͷར༻ https://developer.apple.com/documentation/swift/ concurrency @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS
16.0, *) public protocol Clock<Duration> : Sendable { associatedtype Duration where Self.Duration == Self.Instant.Duration associatedtype Instant : InstantProtocol var now: Self.Instant { get } var minimumResolution: Self.Duration { get } func sleep(until deadline: Self.Instant, tolerance: Self.Instant.Duration?) async throws } • Clockͱ͍͏࠷৽ͷػೳΛར༻
αϯϓϧ https://github.com/pointfreeco/swift-composable-architecture/tree/main/Examples
·ͱΊ • TCAͷαϯϓϧͰԼهͷ͜ͱ͕Ͱ͖Δʂ • TCAͰSwiftͷओʹSwift concurrencyͷར༻ ྫ͕ݟΕΔʂ • TCAͰTCAͷػೳͷɺҰ෦Λ֎෦ϥΠϒϥ Ϧͱͯ͠ར༻͢Δ͜ͱ͕Ͱ͖Δʂ
• TCAͰSwift concurrencyͷ࠷৽ΛΩϟον ΞοϓͰ͖Δʂ
ࠓճௐࠪʹ͝ڠྗ͍͍ͨͩͨΞϓϦ https://github.com/entaku0818/VoiceMemo https://apps.apple.com/jp/app/id6443528409 ⭐ελʔ͍ͩ͘͞ʂʂʂ⭐