Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Sort list based on an @Published variable

I'm building a UI with SwiftUI, and I have an array that I use to build a List element. Now I want to sort that list based on a @Published variable coming from an @EnvironmentObject.

Approach 1

I tried getting the array already sorted, passing in the environment object to the sorting method:

List(getArraySorted(environmentObject)) { item in
    //do stuff with item
}

This will compile, but the list will not update if environmentObject changes. I also tried passing in environmentObject.variableToBaseSortOn but to no avail.

Approach 2

I tried sorting the array inline in Swift UI:

List(array.sorted(by: { (lhs, rhs) -> Bool in
    // do sorting based on self.environmentObject
})) { item in
    // do stuff with item
}

This will compile, but crash:

Fatal error: No ObservableObject of type EnvironmentObjectClass found.
A View.environmentObject(_:) for EnvironmentObjectClass may be missing as an ancestor of this view.

The hint in the crash is incorrect, environmentObject is set and self.environmentObject is set to the correct object.

like image 875
BlackWolf Avatar asked Jan 27 '20 15:01

BlackWolf


1 Answers

Your best approach is probably to sort the list within ObservableObject each time the data changes using a property observer, then manually informing the ObservableObject publisher of the change (rather than using @Published, so the unsorted array is not briefly published between changes.)

It's not a good idea to do the sorting directly in the body of the View because that block may be called many, many times as SwiftUI renders it (this is transparent to us as developers). I suspect that may be a reason that Approach 2 is not working.

For example:

import Combine

class SomeObject: ObservableObject {

    // or whatever data type you need...
    var array: [String] {
        didSet {
            array.sort(by: { (lhs, rhs) -> Bool in
                // do sorting based on self.environmentObject
            })
            objectWillChange.send()
        }
    }

}
like image 174
Bradley Mackey Avatar answered Sep 25 '22 22:09

Bradley Mackey