`Republished` property wrapper enabling nested ObservableObjects in SwiftUI

Republished

The @Republished proprty wrapper allows an ObservableObject nested within another ObservableObject to naturally notify SwiftUI of changes.

It was inspired by @mergesort’s blog post introducing Boutique.

Problem

Nested ObservableObjects don’t play well with SwiftUI.

An ObservableObject is a reference type, not a value type. This means a field on an outer ObservableObject containing an inner ObservableObject doesn’t change when the inner object’s one’s changes. As such the outer object will not send the objectWillChange notification required for SwiftUI to know to rerender views that depend on its data.

Nested ObservableObjects are often a sign your data model needs some refactoring — but it can also be a nice way to separate code concerns. Boutique provides a data store as a nestable ObservableObject. This repo’s Example App uses nested ObservableObjects to separate its ‘DomainModel’ from its ‘ViewModel’, showcasing a version of the MVVM pattern that separates view-display logic from business logic (and is a bit closer to its original form).

Usage

The outer ObservableObject should hold the inner one in a var annotated with the @Republished property wrapper.

@Republished private var inner: InnerObservableObject

The inner ObservableObject's objectWillChange notifications will be re-emitted by the outer ObservableObject, allowing it to provide SwiftUI compatible accessors derived from the inner.

var infoFromInner: String { "\(inner.info)" }

Note: The outer ObservableObject will only republish notifications from inner ObservableObjects that it actually accesses.

SPM

You can use this library via Swift Package Manger by adding a dependency in your Package.swift.

.package(url: "https://github.com/adam-zethraeus/Republished", from: "0.1.0")

Example App

The RepublishedTestApp contains a simple example of an inner ObservableObject, used by an outer ObservableObject view model, to provide data for a regular SwiftUI View.

GitHub

View Github