### Swift Initialization with AnyScheduler Helpers Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Examples of initializing an EpisodeViewModel using AnyScheduler's convenience initializers for production (main DispatchQueue) and testing (immediate scheduler). ```swift let viewModel = EpisodeViewModel( apiClient: ..., scheduler: .main ) let viewModel = EpisodeViewModel( apiClient: ..., scheduler: .immediate ) ``` -------------------------------- ### Testing Asynchronous Publishers with ImmediateScheduler (Swift) Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Provides an example of testing a ViewModel with an asynchronous operation that uses a delay. It contrasts the need for `XCTWaiter` with the simplified testing approach using `ImmediateScheduler`. ```swift class HomeViewModel: ObservableObject { @Published var episodes: [Episode]? let apiClient: ApiClient init(apiClient: ApiClient) { self.apiClient = apiClient } func reloadButtonTapped() { Just(()) .delay(for: .seconds(10), scheduler: DispatchQueue.main) .flatMap { apiClient.fetchEpisodes() } .assign(to: &self.$episodes) } } ``` ```swift func testViewModel() { let viewModel = HomeViewModel(apiClient: .mock) viewModel.reloadButtonTapped() _ = XCTWaiter.wait(for: [XCTestExpectation()], timeout: 10) XCTAssert(viewModel.episodes, [Episode(id: 42)]) } ``` -------------------------------- ### Swift ViewModel using DispatchQueue.main Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md An example of an ObservableObject ViewModel that uses DispatchQueue.main for receiving network responses. This implementation is harder to test due to the direct dependency on a specific concrete scheduler. ```swift class EpisodeViewModel: ObservableObject { @Published var episode: Episode? let apiClient: ApiClient init(apiClient: ApiClient) { self.apiClient = apiClient } func reloadButtonTapped() { self.apiClient.fetchEpisode() .receive(on: DispatchQueue.main) .assign(to: &self.$episode) } } ``` -------------------------------- ### UnimplementedScheduler Example in Swift Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Demonstrates how to use UnimplementedScheduler in Swift to ensure a test fails if a scheduler is unexpectedly used. This is useful for documenting code paths that should not involve asynchronous operations. ```swift class EpisodeViewModel: ObservableObject { @Published var episode: Episode? let apiClient: ApiClient let mainQueue: AnySchedulerOf init(apiClient: ApiClient, mainQueue: AnySchedulerOf) { self.apiClient = apiClient self.mainQueue = mainQueue } func reloadButtonTapped() { self.apiClient.fetchEpisode() .receive(on: self.mainQueue) .assign(to: &self.$episode) } func favoriteButtonTapped() { self.episode?.isFavorite.toggle() } } func testFavoriteButton() { let viewModel = EpisodeViewModel( apiClient: .mock, mainQueue: .unimplemented ) viewModel.episode = .mock viewModel.favoriteButtonTapped() XCTAssert(viewModel.episode?.isFavorite == true) viewModel.favoriteButtonTapped() XCTAssert(viewModel.episode?.isFavorite == false) } ``` -------------------------------- ### Async Concurrency APIs for Schedulers in Swift Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Provides async-friendly APIs for interacting with Combine schedulers in Swift. Includes examples for pausing execution with `sleep` and performing periodic work with `timer`. ```swift // Suspend the current task for 1 second try await scheduler.sleep(for: .seconds(1)) // Perform work every 1 second for await instant in scheduler.timer(interval: .seconds(1)) { ... } ``` -------------------------------- ### Type-Erasing Scheduler with AnyScheduler in Swift Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt Demonstrates using AnyScheduler to type-erase scheduler dependencies, useful for dependency injection without generic constraints. It shows production and test usage examples with main and immediate schedulers, and explicit erasure. ```swift import Combine import CombineSchedulers // View model with type-erased scheduler class EpisodeViewModel: ObservableObject { @Published var episode: Episode? let apiClient: ApiClient let scheduler: AnySchedulerOf init(apiClient: ApiClient, scheduler: AnySchedulerOf) { self.apiClient = apiClient self.scheduler = scheduler } func reloadButtonTapped() { apiClient.fetchEpisode() .receive(on: scheduler) .assign(to: &self.$episode) } } // Production usage with main queue let viewModel = EpisodeViewModel( apiClient: .live, scheduler: .main // Static helper for common schedulers ) // Test usage with immediate scheduler let testViewModel = EpisodeViewModel( apiClient: .mock, scheduler: .immediate // Executes synchronously for testing ) // Alternative: explicitly erase any scheduler let customViewModel = EpisodeViewModel( apiClient: .live, scheduler: DispatchQueue.global(qos: .background).eraseToAnyScheduler() ) ``` -------------------------------- ### SwiftUI Animation Integration with Combine Schedulers Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt Shows how to integrate Combine Schedulers with SwiftUI animations, automatically wrapping state updates within `withAnimation` blocks. This simplifies animations when using operators like `assign(to:)`. Examples include default, custom spring, and transaction-based animations. ```swift import Combine import CombineSchedulers import SwiftUI class ViewModel: ObservableObject { @Published var articles: [Article] = [] let scheduler: AnySchedulerOf var cancellables = Set() init(scheduler: AnySchedulerOf) { self.scheduler = scheduler } func loadArticles() { apiClient.loadArticles() // Automatically animates the assignment .receive(on: scheduler.animation()) .assign(to: &self.$articles) } func loadWithCustomAnimation() { apiClient.loadArticles() .receive(on: scheduler.animation(.spring(response: 0.5, dampingFraction: 0.8))) .assign(to: &self.$articles) } func loadCachedAndFresh() { // Cached articles load without animation cachedArticles() .receive(on: scheduler.animation(nil)) .append( // Fresh articles load with animation apiClient.loadArticles() .receive(on: scheduler.animation(.easeInOut)) ) .assign(to: &self.$articles) } func loadWithTransaction() { var transaction = Transaction() transaction.animation = .spring() transaction.disablesAnimations = false apiClient.loadArticles() .receive(on: scheduler.transaction(transaction)) .assign(to: &self.$articles) } } ``` -------------------------------- ### Async/Await Concurrency with Combine Schedulers Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt Provides modern async/await APIs for schedulers, bridging Combine schedulers and Swift's structured concurrency. These APIs function with all scheduler types, including test schedulers. It supports suspending execution for durations, sleeping until a deadline, and asynchronous timer streams. Also includes examples for testing with TestScheduler and measuring execution time. ```swift import Combine import CombineSchedulers // Suspend execution for a duration func delayedWork() async throws { let scheduler = DispatchQueue.main print("Starting work...") try await scheduler.sleep(for: .seconds(2)) print("2 seconds passed") // With tolerance try await scheduler.sleep( for: .seconds(1), tolerance: .milliseconds(100) ) } // Sleep until a specific deadline func scheduleUntilDeadline() async throws { let scheduler = DispatchQueue.main let deadline = scheduler.now.advanced(by: .seconds(5)) try await scheduler.sleep(until: deadline) print("Reached deadline") } // Async timer stream func processTimerEvents() async throws { let scheduler = DispatchQueue.main for await instant in scheduler.timer(interval: .seconds(1)) { print("Tick at:", instant) if shouldStop { break // Automatically cancels timer } } } // Testing with TestScheduler func testAsyncWork() async { let scheduler = DispatchQueue.test Task { try await scheduler.sleep(for: .seconds(10)) completed = true } XCTAssertFalse(completed) await scheduler.advance(by: 10) XCTAssertTrue(completed) } // Measure execution time func measureWork() { let scheduler = DispatchQueue.main let elapsed = scheduler.measure { performExpensiveWork() } print("Work took:", elapsed) } ``` -------------------------------- ### UIKit Animation Integration with Combine Schedulers Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt Details how to use Combine Schedulers to declaratively animate state changes in UIKit. The scheduler extensions allow wrapping Combine pipeline updates within `UIView.animate` calls. Examples cover basic, custom-option, and spring animations. ```swift import Combine import CombineSchedulers import UIKit class ProfileViewController: UIViewController { let viewModel: ProfileViewModel let scheduler: AnySchedulerOf var cancellables = Set() init(viewModel: ProfileViewModel, scheduler: AnySchedulerOf) { self.viewModel = viewModel self.scheduler = scheduler super.init(nibName: nil, bundle: nil) } override func viewDidLoad() { super.viewDidLoad() // Basic animation viewModel.profilePublisher .receive(on: scheduler.animate(withDuration: 0.3)) .sink { [weak self] profile in self?.updateUI(with: profile) } .store(in: &cancellables) // Animation with custom options viewModel.statusPublisher .receive(on: scheduler.animate( withDuration: 0.5, delay: 0.1, options: [.curveEaseInOut, .allowUserInteraction] )) .sink { [weak self] status in self?.statusLabel.text = status } .store(in: &cancellables) // Spring animation viewModel.alertPublisher .receive(on: scheduler.animate( withDuration: 0.6, delay: 0, usingSpringWithDamping: 0.7, initialSpringVelocity: 0.5, options: [] )) .sink { [weak self] alert in self?.showAlert(alert) } .store(in: &cancellables) } } ``` -------------------------------- ### Create a Repeating Timer with Publishers.Timer (Swift) Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Demonstrates how to create a repeating timer using Publishers.Timer. It specifies the interval and the scheduler to use, then subscribes to its output. This is an alternative to Foundation's Timer.publisher, allowing any scheduler. ```swift Publishers.Timer(every: .seconds(1), scheduler: DispatchQueue.main) .autoconnect() .sink { print("Timer", $0) } ``` -------------------------------- ### Testable Timer with TestScheduler (Swift) Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Illustrates how to use Publishers.Timer with a TestScheduler for easily testable timer logic. It shows how to advance time on the scheduler and assert the timer's output at different points, avoiding the need for actual time delays in tests. ```swift let scheduler = DispatchQueue.test var output: [Int] = [] Publishers.Timer(every: 1, scheduler: scheduler) .autoconnect() .sink { _ in output.append(output.count) } .store(in: &self.cancellables) XCTAssertEqual(output, []) scheduler.advance(by: 1) XCTAssertEqual(output, [0]) scheduler.advance(by: 1) XCTAssertEqual(output, [0, 1]) scheduler.advance(by: 1_000) XCTAssertEqual(output, Array(0...1_001)) ``` -------------------------------- ### ImmediateScheduler for Synchronous Task Execution (Swift) Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Demonstrates using ImmediateScheduler to make asynchronous operations execute synchronously, useful for testing Combine publishers without delays. It allows swapping a live DispatchQueue with an immediate one. ```swift class HomeViewModel: ObservableObject { @Published var episodes: [Episode]? let apiClient: ApiClient let scheduler: AnySchedulerOf init(apiClient: ApiClient, scheduler: AnySchedulerOf) { self.apiClient = apiClient self.scheduler = scheduler } func reloadButtonTapped() { Just(()) .delay(for: .seconds(10), scheduler: self.scheduler) .flatMap { self.apiClient.fetchEpisodes() } .assign(to: &self.$episodes) } } ``` ```swift func testViewModel() { let viewModel = HomeViewModel( apiClient: .mock, scheduler: .immediate ) viewModel.reloadButtonTapped() // No more waiting... XCTAssert(viewModel.episodes, [Episode(id: 42)]) } ``` -------------------------------- ### Create a Repeating Timer using Scheduler Extension (Swift) Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Shows how to create a repeating timer by calling the timerPublisher method directly on a scheduler instance. This provides a more concise way to achieve the same functionality as Publishers.Timer. ```swift DispatchQueue.main.timerPublisher(every: .seconds(1)) .autoconnect() .sink { print("Timer", $0) } ``` -------------------------------- ### Swift ViewModel with Generic Scheduler Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md A generic ViewModel that accepts any conforming Scheduler. This approach allows for easy dependency injection of schedulers for testing but introduces complexity with generics. ```swift class EpisodeViewModel: ObservableObject { @Published var episode: Episode? let apiClient: ApiClient let scheduler: S init(apiClient: ApiClient, scheduler: S) { self.apiClient = apiClient self.scheduler = scheduler } func reloadButtonTapped() { self.apiClient.fetchEpisode() .receive(on: self.scheduler) .assign(to: &self.$episode) } } ``` -------------------------------- ### Advanced Test Scheduler Usage with Combine Schedulers Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt Demonstrates advanced patterns for testing complex timing scenarios using TestScheduler within the Combine Schedulers library. This includes running schedulers to completion and testing debounce/throttle operators. It showcases how to simulate rapid events, manage debounce windows, and handle sequential timer emissions. ```swift import Combine import CombineSchedulers import XCTest func testDebounce() { let scheduler = DispatchQueue.test let subject = PassthroughSubject() var output: [String] = [] subject .debounce(for: .seconds(1), scheduler: scheduler) .sink { output.append($0) } .store(in: &cancellables) // Send rapid events subject.send("a") subject.send("b") subject.send("c") scheduler.advance(by: 0.5) // Nothing debounced yet XCTAssertEqual(output, []) // Complete debounce window scheduler.advance(by: 0.6) XCTAssertEqual(output, ["c"]) // New events subject.send("d") scheduler.advance(by: 1) XCTAssertEqual(output, ["c", "d"]) } func testSchedulerRun() { let scheduler = DispatchQueue.test var output: [Int] = [] // Timer that would run forever Publishers.Timer(every: .seconds(1), scheduler: scheduler) .autoconnect() .prefix(5) // Limit to 5 emissions .sink { _ in output.append(output.count) } .store(in: &cancellables) // Run scheduler until all work completes scheduler.run() // All 5 timer events processed instantly XCTAssertEqual(output, [0, 1, 2, 3, 4]) } func testComplexTimingScenario() { let scheduler = DispatchQueue.test let subject = PassthroughSubject() var output: [(time: DispatchQueue.SchedulerTimeType, value: Int)] = [] subject .flatMap { Just($0) .delay(for: .seconds($0), scheduler: scheduler) } .sink { output.append((scheduler.now, $0)) } .store(in: &cancellables) subject.send(1) subject.send(3) subject.send(2) scheduler.advance(by: 1) XCTAssertEqual(output.map(\.value), [1]) scheduler.advance(by: 1) XCTAssertEqual(output.map(\.value), [1, 2]) scheduler.advance(by: 1) XCTAssertEqual(output.map(\.value), [1, 2, 3]) } ``` -------------------------------- ### Swift: Race two futures with TestScheduler Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Demonstrates using a TestScheduler to race two futures, controlling their emission times to test asynchronous behavior. The scheduler's time can be advanced to trigger emissions and verify publisher output. ```swift func race( _ first: Future, _ second: Future ) -> AnyPublisher { first .merge(with: second) .prefix(1) .eraseToAnyPublisher() } let scheduler = DispatchQueue.test let first = Future { callback in scheduler.schedule(after: scheduler.now.advanced(by: 1)) { callback(.success(1)) } } let second = Future { callback in scheduler.schedule(after: scheduler.now.advanced(by: 2)) { callback(.success(2)) } } var output: [Int] = [] let cancellable = race(first, second).sink { output.append($0) } scheduler.advance(by: 1) XCTAssertEqual(output, [1]) scheduler.advance(by: 1) XCTAssertEqual(output, [1]) ``` -------------------------------- ### Animating SwiftUI State Mutations with CombineSchedulers (Swift) Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Shows how to animate SwiftUI state changes triggered by Combine publishers using the `animation()` method on a scheduler. This mirrors SwiftUI's `withAnimation` for smoother UI updates. ```swift self.apiClient.fetchEpisode() .receive(on: self.scheduler.animation()) .assign(to: &self.$episode) ``` -------------------------------- ### Animating UIKit Operations with CombineSchedulers (Swift) Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md Illustrates animating UIKit view updates driven by Combine publishers using the `.animate()` method on a scheduler. This functionality is akin to `UIView.animate` for synchronizing Combine emissions with UIKit animations. ```swift self.apiClient.fetchEpisode() .receive(on: self.scheduler.animate(withDuration: 0.3)) .assign(to: &self.$episode) ``` -------------------------------- ### Deterministic Time Control with TestScheduler in Swift Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt Illustrates how to use TestScheduler for deterministic control over time in tests. This is crucial for testing time-based Combine operators like debounce, throttle, and delay without waiting for real time. ```swift import Combine import CombineSchedulers import XCTest func testRaceCondition() { let scheduler = DispatchQueue.test // Create two futures with different delays let first = Future { callback in scheduler.schedule(after: scheduler.now.advanced(by: 1)) { callback(.success(1)) } } let second = Future { callback in scheduler.schedule(after: scheduler.now.advanced(by: 2)) { callback(.success(2)) } } // Race the futures var output: [Int] = [] let cancellable = first .merge(with: second) .prefix(1) .sink { output.append($0) } // Initially nothing emitted XCTAssertEqual(output, []) // Advance time by 1 second - first future completes scheduler.advance(by: 1) XCTAssertEqual(output, [1]) // Advance time by 1 more second - no new output (already prefixed) scheduler.advance(by: 1) XCTAssertEqual(output, [1]) // Run scheduler until all scheduled work completes scheduler.run() } ``` -------------------------------- ### ImmediateScheduler: Synchronous Execution in Swift Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt ImmediateScheduler executes all work synchronously without delays. It's ideal for testing scenarios where asynchronous waits should be avoided. This scheduler collapses all specified delays to zero, ensuring immediate execution of Combine operations. ```swift import Combine import CombineSchedulers import XCTest class HomeViewModel: ObservableObject { @Published var episodes: [Episode]? let apiClient: ApiClient let scheduler: AnySchedulerOf init(apiClient: ApiClient, scheduler: AnySchedulerOf) { self.apiClient = apiClient self.scheduler = scheduler } func reloadButtonTapped() { Just(()) .delay(for: .seconds(10), scheduler: scheduler) .flatMap { self.apiClient.fetchEpisodes() } .assign(to: &self.$episodes) } } // Test without waiting 10 seconds func testViewModel() { let viewModel = HomeViewModel( apiClient: .mock, scheduler: .immediate // Collapses all delays to immediate ) viewModel.reloadButtonTapped() // No XCTWaiter needed - executes immediately XCTAssertEqual(viewModel.episodes, [Episode(id: 42)]) } // Production usage maintains real delays let productionViewModel = HomeViewModel( apiClient: .live, scheduler: .main ) ``` -------------------------------- ### UIScheduler: Immediate Main Thread Execution in Swift Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt Demonstrates using UIScheduler to perform work immediately on the main thread when already on it, preventing unnecessary thread hops. This is beneficial for performance-critical UI operations. It shows direct usage and type-erased AnyScheduler instantiation. ```swift import Combine import CombineSchedulers import UIKit class AnimationController { let scheduler = UIScheduler.shared var cancellables = Set() func setupAnimation() { // UIScheduler executes immediately on main thread if already there // No thread hop like DispatchQueue.main would cause dataPublisher .receive(on: scheduler) .sink { [weak self] data in self?.updateUI(with: data) // Executes immediately on main thread } .store(in: &cancellables) } } // Using as type-erased AnyScheduler class ViewModel { let scheduler: AnyScheduler init(scheduler: AnyScheduler = .shared) { self.scheduler = scheduler } func process() { publisher .receive(on: scheduler) .sink { value in // Immediate execution if on main thread } .store(in: &cancellables) } } // Test with immediate scheduler let testVM = ViewModel(scheduler: .immediate) ``` -------------------------------- ### TestScheduler: Advanced Timer Control in Swift Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt TestScheduler enables advanced timer testing by simulating time passage instantly. It's invaluable for testing repeating timers and periodic tasks without slowing down test execution. You can advance time by specific intervals or by large amounts to verify timer-based logic. ```swift import Combine import CombineSchedulers import XCTest func testTimerPublisher() { let scheduler = DispatchQueue.test var output: [Int] = [] var cancellables = Set() // Create a timer that fires every second Publishers.Timer(every: .seconds(1), scheduler: scheduler) .autoconnect() .sink { _ in output.append(output.count) } .store(in: &cancellables) // Nothing emitted yet XCTAssertEqual(output, []) // Advance 1 second scheduler.advance(by: 1) XCTAssertEqual(output, [0]) // Advance 1 more second scheduler.advance(by: 1) XCTAssertEqual(output, [0, 1]) // Simulate 1,000 seconds passing instantly scheduler.advance(by: 1_000) XCTAssertEqual(output, Array(0...1_001)) } // Using timerPublisher extension func testSchedulerTimerExtension() { let scheduler = DispatchQueue.test var output: [DispatchQueue.SchedulerTimeType] = [] var cancellables = Set() scheduler.timerPublisher(every: .seconds(5)) .autoconnect() .prefix(3) .sink { output.append($0) } .store(in: &cancellables) scheduler.advance(by: 15) XCTAssertEqual(output.count, 3) } ``` -------------------------------- ### Swift ViewModel using AnySchedulerOf Source: https://github.com/pointfreeco/combine-schedulers/blob/main/README.md An ObservableObject ViewModel utilizing AnySchedulerOf to hold a type-erased scheduler. This version avoids generics in the ViewModel's definition while allowing for scheduler substitution. ```swift class EpisodeViewModel: ObservableObject { @Published var episode: Episode? let apiClient: ApiClient let scheduler: AnySchedulerOf init(apiClient: ApiClient, scheduler: AnySchedulerOf) { self.apiClient = apiClient self.scheduler = scheduler } func reloadButtonTapped() { self.apiClient.fetchEpisode() .receive(on: self.scheduler) .assign(to: &self.$episode) } } ``` -------------------------------- ### UnimplementedScheduler: Asserting No Scheduling in Swift Source: https://context7.com/pointfreeco/combine-schedulers/llms.txt UnimplementedScheduler fails tests if it is ever invoked, serving as a clear assertion that certain code paths should not involve scheduling. This makes tests more explicit about their dependencies and helps catch unintended scheduling operations. It can be initialized with a custom error message for clarity. ```swift import Combine import CombineSchedulers import XCTest class EpisodeViewModel: ObservableObject { @Published var episode: Episode? let apiClient: ApiClient let mainQueue: AnySchedulerOf init(apiClient: ApiClient, mainQueue: AnySchedulerOf) { self.apiClient = apiClient self.mainQueue = mainQueue } func reloadButtonTapped() { apiClient.fetchEpisode() .receive(on: mainQueue) // Uses scheduler .assign(to: &self.$episode) } func favoriteButtonTapped() { episode?.isFavorite.toggle() // Doesn't use scheduler } } // Test that documents no scheduling is needed func testFavoriteButton() { let viewModel = EpisodeViewModel( apiClient: .mock, mainQueue: .unimplemented // Will fail test if scheduler is used ) viewModel.episode = .mock viewModel.favoriteButtonTapped() XCTAssert(viewModel.episode?.isFavorite == true) viewModel.favoriteButtonTapped() XCTAssert(viewModel.episode?.isFavorite == false) } // Test with custom prefix for better error messages func testAnotherFeature() { let viewModel = EpisodeViewModel( apiClient: .mock, mainQueue: .unimplemented("testAnotherFeature") ) // If scheduler is used, error will include "testAnotherFeature" prefix } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.