Skip to content
This repository has been archived by the owner on Jun 23, 2023. It is now read-only.

Latest commit

 

History

History
57 lines (37 loc) · 2.38 KB

UpdatingInterface.md

File metadata and controls

57 lines (37 loc) · 2.38 KB

Updating Interface

Context

Changes from Domain that can change over time are exposed as a Combine publishers. Using publishers is a very good way of broadcasting changes. Unfortunately, currently there is a mismatch between how publishers are provided, and how UIKit and SwiftUI expect to consume them.

Using publishers in UIKit is somewhat awkward, as we need to add a sink, manage cancellable, and make sure we pass the data to the main thread.

Using publishers in SwiftUI is inconvenient in a different way: In order for SwiftUI to be notified of changes, publishers need to be wrapped into an ObservableObject. Also, we still need to make sure the updates happen on the main thread.

InterfaceProperty

InterfaceProperty type is here to help with these issues. Currently, this focuses on integration with SwiftUI. We will add more ergonomic way of using InterfaceProperty from UIKit in the future.

Updating SwiftUI Views

InterfaceProperty type conforms to ObservableObject protocol. This means we can pass it and use it from a SwiftUI.View as is:

public struct RiskView: View {
    @ObservedProperty private var isRisky: InterfaceProperty<Bool>

    public init(isRisky: InterfaceProperty<Bool>) {
        self.isRisky = isRisky
    }

    public var body: some View {
        Text(isRisky.wrappedValue ? "Risky" : "Not risky")
    }
}

You can create an InterfaceProperty from a publisher:

var isRisky: AnyPublisher<Bool, Never> = ...
RiskView(isRisky: isRisky.property(initialValue: false))

Or (usually in Scenarios) from a constant value:

RiskView(isRisky: .constant(false))

Internally, InterfaceProperty ensures its value only changes on the main thread. So there’s no need for manual thread configuration.

Unfortunately, there is still some boilerplate when using InterfaceProperty types inside view models – in particular, to make sure the objectWillChange publisher is passed along correctly. For an example of how this is done, see RiskLevelBanner.ViewModel.