UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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 Essential Developer

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until April 28th.

Click to save your free 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.