Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TCAでiOS開発を_学ぶ3つの利点.pdf

entaku
November 14, 2023
170

 TCAでiOS開発を_学ぶ3つの利点.pdf

entaku

November 14, 2023
Tweet

Transcript

  1. entaku • name: entaku • job: iOSΤϯδχΞͳͲ • SIer໿6೥ •

    εϙʔπϚονϯάΞϓϦ1೥ • ෺ྲྀITαʔϏε ໿2೥ • Voicy • Twitter • @entaku_0818
  2. ͜Ε·Ͱͷ࿥Իॲཧ 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)") } } }
  3. ࿥ԻॲཧͰ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Ͱ࿥ԻͷඇಉظॲཧΛ࣮ݱ
  4. ࿥ԻॲཧͰ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 • ੒ޭ࣌ͷॲཧͷΈΞϓϦଆʹॻ͚ΔΑ͏ʹͳΔ
  5. ґଘੑͷ࢓૊Έ 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
  6. ґଘੑͷ࢓૊Έ 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") ) }
  7. 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 } • ࿥Ի࣌ͷλΠϚʔॲཧ
  8. 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ͱ͍͏࠷৽ͷػೳΛར༻