Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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
140
AVAudioSessionの全体像を掴む.pdf
entaku
0
200
Core_Audio徹底解剖.pdf
entaku
4
450
わたしと今年のSwift.pdf
entaku
1
210
個人開発をTCAで運用していくということ.pdf
entaku
0
83
パッケージ管理でモバイル開発を安全に進める.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
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
400
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Fireside Chat
paigeccino
43
4k
Statistics for Hackers
jakevdp
799
230k
Building a Scalable Design System with Sketch
lauravandoore
464
34k
Code Review Best Practice
trishagee
74
20k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Designing Experiences People Love
moore
143
24k
Site-Speed That Sticks
csswizardry
13
1.5k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
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 ⭐ελʔ͍ͩ͘͞ʂʂʂ⭐