GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

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 try! Swift Tokyo.

SPONSORED Ready to dive into the world of Swift? try! Swift Tokyo is the premier iOS developer conference will be happened in April 9th-11th, where you can learn from industry experts, connect with fellow developers, and explore the latest in Swift and iOS development. Don’t miss out on this opportunity to level up your skills and be part of the Swift community!

Get your ticket here

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.