Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Making a Combine publisher from a FetchedResultsController
//
// FetchedResultsControllerPublisher.swift
// ListsModel
//
// Created by Joseph Lord on 09/06/2019.
// Copyright © 2019 Joseph Lord. All rights reserved.
//
import Foundation
import Combine
import CoreData
/// Create by passing in a FetchedResultsController
/// This will perform the fetch request on the correct queue and publish the resutls on the
/// publishers.
final public class FetchedResultsControllerPublisher<FetchType>
where FetchType : NSFetchRequestResult {
private let internalFRCP: FetchedResultsControllerPublisherInternal<FetchType>
/// Pass in a configured fetchResults controller and this class will provide a choice of publishers
/// for you depending on how you like your errors
public init(fetchedResultsController: NSFetchedResultsController<FetchType>,
performFetchNotRequired: Bool = false) {
self.internalFRCP = FetchedResultsControllerPublisherInternal(
fetchedResultsController: fetchedResultsController,
performFetch: !performFetchNotRequired)
}
public lazy var publisherWithErrors: AnyPublisher<[FetchType], Error> = {
return self.internalFRCP.publisher.eraseToAnyPublisher()
}()
public lazy var publisher: AnyPublisher<[FetchType], Never> = {
return self.internalFRCP.publisher.replaceError(with: []).eraseToAnyPublisher()
}()
}
final private class FetchedResultsControllerPublisherInternal<FetchType>
: NSObject, NSFetchedResultsControllerDelegate
where FetchType : NSFetchRequestResult {
let publisher: PassthroughSubject<[FetchType], Error>
let fetchedResultsController: NSFetchedResultsController<FetchType>
init(fetchedResultsController: NSFetchedResultsController<FetchType>,
performFetch: Bool) {
self.fetchedResultsController = fetchedResultsController
publisher = PassthroughSubject<[FetchType], Error>()
super.init()
fetchedResultsController.delegate = self
fetchedResultsController.managedObjectContext.perform {
do {
if performFetch {
try fetchedResultsController.performFetch()
}
self.publisher.send(fetchedResultsController.fetchedObjects ?? [])
} catch {
self.publisher.send(completion: .failure(error))
}
}
}
@objc func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
publisher.send(fetchedResultsController.fetchedObjects ?? [])
}
}
@kielgillard

This comment has been minimized.

Copy link

kielgillard commented Jul 30, 2019

@josephlord

This comment has been minimized.

Copy link
Owner Author

josephlord commented Jul 30, 2019

Yes. This is probably completely redundant now

@jjatie

This comment has been minimized.

Copy link

jjatie commented Aug 26, 2019

It's still nice to process results from an FRC using Combine, especially when not driving views.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.