Skip to content

Instantly share code, notes, and snippets.

@ericlewis
Created September 24, 2020 22:44
Show Gist options
  • Save ericlewis/25310a719cba4f97e798aa5c238de77e to your computer and use it in GitHub Desktop.
Save ericlewis/25310a719cba4f97e798aa5c238de77e to your computer and use it in GitHub Desktop.
//
// LPMetadataProvider+Combine.swift
// Hacker
//
// Created by Eric Lewis on 9/22/20.
//
import SwiftUI
import LinkPresentation
import Combine
class MetadataProvider: ObservableObject {
@Published var metadata: LPLinkMetadata?
@Published var image: UIImage?
@Published var icon: UIImage?
@Published var error: Error?
var cancellable: AnyCancellable?
var imageCancellable: AnyCancellable?
var iconCancellable: AnyCancellable?
private var provider = LPMetadataProvider()
func fetch(url: URL) {
error = nil
cancellable = provider.startFetchingMetadataPublisher(for: url)
.receive(on: RunLoop.main)
.sink(receiveCompletion: { [weak self] completion in
switch completion {
case .finished:
break
case .failure(let error):
self?.error = error
}
}) { [weak self] metadata in
guard let `self` = self else {
return
}
self.metadata = metadata
self.imageCancellable = metadata?.imageProvider?.loadObjectPublisher(forClass: UIImage.self)
.receive(on: RunLoop.main)
.catch { _ in Just(nil) }
.assign(to: \.image, on: self)
self.iconCancellable = metadata?.iconProvider?.loadObjectPublisher(forClass: UIImage.self)
.receive(on: RunLoop.main)
.catch { _ in Just(nil) }
.assign(to: \.icon, on: self)
}
}
deinit {
cancellable?.cancel()
imageCancellable?.cancel()
iconCancellable?.cancel()
}
}
extension LPMetadataProvider {
func startFetchingMetadataPublisher(for url: URL) -> AnyPublisher<LPLinkMetadata?, Error> {
Future<LPLinkMetadata?, Error> { [weak self] completion in
self?.startFetchingMetadata(for: url) { meta, error in
guard let error = error else {
return completion(.success(meta))
}
completion(.failure(error))
}
}
.handleEvents(receiveCancel: { [weak self] in
self?.cancel()
})
.eraseToAnyPublisher()
}
}
extension NSItemProvider {
func loadObjectPublisher<T>(forClass: T.Type) -> AnyPublisher<T?, Error> where T: NSItemProviderReading {
Future<T?, Error> { [weak self] completion in
self?.loadObject(ofClass: T.self) { item, error in
guard let error = error else {
return completion(.success(item as? T))
}
completion(.failure(error))
}
}
.eraseToAnyPublisher()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment