TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

How to migrate @Published with Combine to the new @Obserbable?

Forums > Swift

Hi!

While the @Obsevable macro seems to make things easier at first glance, I am struggling to understand how to implement some scenarious using the new observability model - most importantly, how to observe properties within the same model class.

For example, consider the following model:

class MyModel: ObservableObject {

    @Published var items = ["one", "two", "three"]

    @Published var filter: String? = nil

    @Published var filteredItems: [String] = []

    init() {
        $filter
            .combineLatest($items)
            .map { filter, items in
                items.filter { filter == nil || $0.contains(filter!) }
            }
            .assign(to: &$filteredItems)
    }
}

All @Published properties are easily accessible by the view, but I can also combine them inside the init method to compute filtered items whenever any of these values change. I don't seem to find a soluton for this using @Observable.

I tried using withObservationTracking, but this ends up with the view being continously redrawn. I tried to use this gist with the same effect: https://gist.github.com/SmartJSONEditor/33d796e81554205fd491b6449376c426.

@Observable class MyModel1 {

    var items = ["one", "two", "three"]

    var filter: String? = nil

    var filteredItems: [String] = []

    init() {
        let filter = publisher(keyPath: \MyModel1.filter)
        let items = publisher(keyPath: \MyModel1.items)

        filter
            .combineLatest(items)
            .map { filter, items in
                items.filter { filter == nil || $0.contains(filter!) }
            }
            .sink { filteredItems in
                self.filteredItems = filteredItems
            }
    }
}

In the official observability proposal from Swift there is an example from the Fruta app, but this example uses a computed property. It does work in some cases, but it requires an observer and if there are more than one, the whole conputation is executed multiple times.

@Observable class MyModel2 {
    var items = ["one", "two", "three"]

    var filter: String? = nil

    var filteredItems: [String] {
        items.filter { filter == nil || $0.contains(filter!) }
    }
}

4      

Same question, I actaully really like how Combine does there piplines with sink.

I ended up getting around this need with a didSet on my variable but I really hope we can expect publisher support in the next release? please!?

2      

Hacking with Swift is sponsored by Blaze.

SPONSORED Still waiting on your CI build? Speed it up ~3x with Blaze - change one line, pay less, keep your existing GitHub workflows. First 25 HWS readers to use code HACKING at checkout get 50% off the first year. Try it now for free!

Reserve your spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.