Skip to content

Instantly share code, notes, and snippets.

@antonio081014
Last active September 9, 2022 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antonio081014/3707b78ab7614ae7472098b4e54480fb to your computer and use it in GitHub Desktop.
Save antonio081014/3707b78ab7614ae7472098b4e54480fb to your computer and use it in GitHub Desktop.
import Foundation
import Combine
class FileSubscription<S: Subscriber>: Subscription
where S.Input == Data, S.Failure == Error {
// fileURL is the url of the file to read
private let fileURL: URL
private var subscriber: S?
init(fileURL: URL, subscriber: S) {
self.fileURL = fileURL
self.subscriber = subscriber
}
func request(_ demand: Subscribers.Demand) {
// Load the file at fileURL only when demand is
// greater than 0, meaning subscribers were added
// to this subscription and demand values
if demand > 0 {
do {
// Success case, data is loaded and this
// subscription finishes
let data = try Data(contentsOf: fileURL)
subscriber?.receive(data)
subscriber?.receive(completion: .finished)
}
catch let error {
// Failure case, this subscription finishes
// and propagates the error
subscriber?.receive(
completion: .failure(error)
)
}
}
}
// Set the subscriber reference to nil, cancelling
// the subscription
func cancel() {
subscriber = nil
}
}
struct FilePublisher: Publisher {
// The output type of FilePublisher publisher
// is Data, which will be the Data of the read file
typealias Output = Data
typealias Failure = Error
// fileURL is the url of the file to read
let fileURL: URL
func receive<S>(subscriber: S) where S : Subscriber,
Failure == S.Failure, Output == S.Input {
// Create a FileSubscription for the new subscriber
// and set the file to be loaded to fileURL
let subscription = FileSubscription(
fileURL: fileURL,
subscriber: subscriber
)
subscriber.receive(subscription: subscription)
}
}
// This is how to use it.
// Then, sink this Publisher and store the AnyCancellable to your local properties.
public final class DiskDataModelClient {
func get(from fileURL: URL) -> AnyPublisher<Data, Error> {
return FilePublisher(fileURL: fileURL)
.subscribe(on: DispatchQueue.global())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment