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
270
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
170
Core_Audio徹底解剖.pdf
entaku
4
420
わたしと今年のSwift.pdf
entaku
1
210
個人開発をTCAで運用していくということ.pdf
entaku
0
75
パッケージ管理でモバイル開発を安全に進める.pdf
entaku
0
1.3k
個人開発をTCAで運用していくということ.pdf
entaku
0
1.4k
技術コミュニティで技術書典出してみた.pdf
entaku
0
130
What_s_new_in_voice_processing他What_s_new_in_Audio.pdf
entaku
1
320
Featured
See All Featured
The Limits of Empathy - UXLibs8
cassininazir
1
350
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
140
Typedesign – Prime Four
hannesfritz
42
3.1k
Making the Leap to Tech Lead
cromwellryan
135
9.9k
Google's AI Overviews - The New Search
badams
0
1k
From π to Pie charts
rasagy
0
200
BBQ
matthewcrist
89
10k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6k
The browser strikes back
jonoalderson
0
1.2k
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
580
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
720
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
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 ⭐ελʔ͍ͩ͘͞ʂʂʂ⭐