Changing computed property in swift

1.7k views Asked by At

I'm having NSFetchedResultsController as lazy computed property. Based on a variable, sort descriptor is created. Here's my code:

private var sortOption: Options = .none
fileprivate lazy var inspirationsResults: NSFetchedResultsController<Inspiration> = {
    // Create Fetch Request
    let fetchRequest: NSFetchRequest<Inspiration> = Inspiration.fetchRequest()

    // Configure Fetch Request
    //let optn = self.sortOption.rawValue
    switch (self.sortOption) {
    case .sortAscending:
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "inspirationName", ascending: true)]
    case .sortDescending:
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "inspirationName", ascending: false)]
    case .sortByAdding:
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: false)]
    case .sortByUpdated:
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: false)]
    case .showFilter:
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: false)]
    default:
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: false)]
    }
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: false)]
    fetchRequest.fetchBatchSize = 10
    // Create Fetched Results Controller
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataManager.shared.getContext(), sectionNameKeyPath: nil, cacheName: nil)

    // Configure Fetched Results Controller
    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

When sortOption variable's value is changed, I want to recompute "inspirationsResults" variable and change the sort descriptor accordingly. How to achieve it?

3

There are 3 answers

0
vadian On BEST ANSWER

Put the code to compute the sort descriptor into the didSet observer of the sortOption property:

private var sortOption: Options = .none {
    didSet {
        let sortDescriptor : NSSortDescriptor
        switch sortOption {
            case .sortAscending:
                sortDescriptor = NSSortDescriptor(key: "inspirationName", ascending: true)
            case .sortDescending:
                sortDescriptor = NSSortDescriptor(key: "inspirationName", ascending: false)
            default:
                sortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)
         }
         fetchedResultsController.fetchRequest.sortDescriptors = [sortDescriptor]
         do {
            try fetchedResultsController.performFetch()
            tableView.reloadData()
         } catch {
            print(error)
         }
    }
}

The default case covers all explicit cases which sort by timeStamp - false.
After changing the sort descriptor you need to perform a new fetch and reload the table view.

And in the method to initialize the results controller simply write:

self.sortOption = .none
3
Tom Harrington On

If you change the declaration of inspirationsResults to be an implicitly unwrapped optional

fileprivate lazy var inspirationsResults: NSFetchedResultsController<Inspiration>! = { ...

...then you can force it to reinitialize by setting its value to nil. As in, if you set inspirationsResults to nil, then the next time you access it, the initialization code runs again. Using an implicitly unwrapped optional is safe here as long as your initialization code never returns nil.

You could then set inspirationResults to nil in the didSet observer for sortOption. The next time you use inspirationResults you'll get a new version with new sorting.

0
Duncan C On

I believe that a property declared as lazy can't be changed once it's set.

You can create the same thing yourself using a property with a custom getter that returns a private property that's created if it's nil. Have the setter for sortOption set the private property to nil to force it to be recalculated.