Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array of BindableObjects SwiftUI

So I'm trying to setup CoreData with SwiftUI and both the CoreData model and SwiftUI views are working. All I need to do is connect them. I am able to pass a discrete number of BindableObjects but what I need is to pass an array. Here's the setup:

let peristence = PersistenceManager()
var model = [Entry]() // Entry Conforms to NSManagedObject and BindableObject
let request = Entry.createFetchRequest()
let sort = NSSortDescriptor(key: "callsign", ascending: true)
request.sortDescriptors = [sort]
do {
    model = try peristence.persistenceContainer.viewContext.fetch(request)
} catch {
    fatalError(error.localizedDescription)
}

if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(model))

Which produces the following error:

Instance method 'environmentObject' requires that '[Entry]' conform to 'BindableObject'

How would I make [Entry] conformant?

like image 718
Brandon Bradley Avatar asked Jul 04 '19 12:07

Brandon Bradley


1 Answers

You can use a NSFetchedResultsControllerDelegate that implements BindableObject protocol and forwards the changes on a NSFetchedResultsController

class BindableFetchedResults<ResultType>: NSObject, BindableObject, NSFetchedResultsControllerDelegate where ResultType : NSFetchRequestResult {

    let controller: NSFetchedResultsController<ResultType>
    var results: [ResultType]? {
        controller.fetchedObjects
    }
    let didChange = PassthroughSubject<Void, Never>()

    init?(fetchRequest: NSFetchRequest<ResultType>, managedObjectContext context: NSManagedObjectContext) {
        self.controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        super.init()
        self.controller.delegate = self
        do {
            try controller.performFetch()
        } catch {
            return nil
        }
    }

    func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
        didChange.send()
    }
}

In the code, something like this:


let persistence = PersistenceManager()
let request = Entry.createFetchRequest()
let sort = NSSortDescriptor(key: "callsign", ascending: true)
request.sortDescriptors = [sort]

guard let model =  BindableFetchedResults(fetchRequest: request, managedObjectContext: persistence.persistenceContainer.viewContext) else {
    fatalError()
}

if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(model))

Then you can access the entities on model.results

like image 51
jla Avatar answered Oct 21 '22 21:10

jla