Awesome
Perception
Observation tools for platforms that do not officially support observation.
Learn More
This library was created by Brandon Williams and Stephen Celis, who host the Point-Free video series which explores advanced Swift language concepts.
<a href="https://www.pointfree.co/"> <img alt="video poster image" src="https://d3rccdn33rt8ze.cloudfront.net/episodes/0252.jpeg" width="600"> </a>Overview
The Perception library provides tools that mimic @Observable
and withObservationTracking
in
Swift 5.9, but they are backported to work all the way back to iOS 13, macOS 10.15, tvOS 13 and
watchOS 6. This means you can start taking advantage of Swift 5.9's observation tools today,
even if you can't drop support for older Apple platforms. Using this library's tools works almost
exactly as using the official tools, but with one small exception.
To begin, mark a class as being observable by using the @Perceptible
macro instead of the
@Observable
macro:
@Perceptible
class FeatureModel {
var count = 0
}
Then you can hold onto a perceptible model in your view using a regular let
property:
struct FeatureView: View {
let model: FeatureModel
// ...
}
And in the view's body
you must wrap your content using the WithPerceptionTracking
view in
order for observation to be correctly hooked up:
struct FeatureView: View {
let model: FeatureModel
var body: some View {
WithPerceptionTracking {
Form {
Text(model.count.description)
Button("Increment") { model.count += 1 }
}
}
}
}
It's unfortunate to have to wrap your view's content in WithPerceptionTracking
, however if you
forget then you will helpfully get a runtime warning letting you know that observation is not
set up correctly:
🟣 Runtime Warning: Perceptible state was accessed but is not being tracked. Track changes to state by wrapping your view in a 'WithPerceptionTracking' view. This must also be done for any escaping, trailing closures, such as 'GeometryReader',
LazyVStack
(and all lazy views), navigation APIs ('sheet', 'popover', 'fullScreenCover', etc.), and others.
Bindable
SwiftUI's @Bindable
property wrapper has also been backported to support perceptible objects. You
can simply qualify the property wrapper with the Perception
module:
struct FeatureView: View {
@Perception.Bindable var model: FeatureModel
// ...
}
Environment
SwiftUI's @Environment
property wrapper and environment
view modifier's support for observation
has also been backported to support perceptible objects using the exact same APIs:
struct FeatureView: View {
@Environment(Settings.self) var settings
// ...
}
// In some parent view:
.environment(settings)
Community
If you want to discuss this library or have a question about how to use it to solve a particular problem, there are a number of places you can discuss with fellow Point-Free enthusiasts:
- For long-form discussions, we recommend the discussions tab of this repo.
- For casual chat, we recommend the Point-Free Community Slack.
Documentation
The latest documentation for the Perception APIs is available here.
License
This library is released under the MIT license. See LICENSE for details.