AI prompts
base on Observable tools, backported. # Perception
[](https://github.com/pointfreeco/swift-perception/actions/workflows/ci.yml)
[](https://www.pointfree.co/slack-invite)
[](https://swiftpackageindex.com/pointfreeco/swift-perception)
[](https://swiftpackageindex.com/pointfreeco/swift-perception)
Swift's Observation tools, back-ported to more platforms.
## Learn More
This library was created by [Brandon Williams][mbrandonw] and [Stephen Celis][stephencelis], who
host the [Point-Free][pointfreeco] 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 back-ports `@Observable`, `withObservationTracking`, and `Observations` all
the way back to iOS 13, macOS 10.15, tvOS 13 and watchOS 6. This means you can take advantage of
all of Swift'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, with one small
exception.
To begin, mark a class as being observable by using the `@Perceptible` macro instead of the
`@Observable` macro:
```swift
@Perceptible
class FeatureModel {
var count = 0
}
```
Then you can hold onto a perceptible model in your view using a regular `let` property:
```swift
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:
```swift
struct FeatureView: View {
let model: FeatureModel
var body: some View {
WithPerceptionTracking {
Form {
Text("\(model.count)")
Button("Increment") { model.count += 1 }
}
}
}
}
```
It's unfortunate to have to wrap your view's content in `WithPerceptionTracking`, but 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 from a view but is not being tracked.
Finally, the `Observations` async sequence has been back-ported as `Perceptions`, which can be used
to observe changes to perceptible and observable objects over time:
```swift
let counts = Perceptions { model.count }
for await count in counts {
print("Count changed: \(count)")
}
```
### Bindable
SwiftUI's `@Bindable` property wrapper has also been back-ported to support perceptible objects. You
can simply qualify the property wrapper with the `Perception` module:
```swift
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 back-ported to support perceptible objects using the exact same APIs:
```swift
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](https://www.pointfree.co) enthusiasts:
* For long-form discussions, we recommend the
[discussions](https://github.com/pointfreeco/swift-perception/discussions) tab of this repo.
* For casual chat, we recommend the
[Point-Free Community Slack](https://pointfree.co/slack-invite).
## Documentation
The latest documentation for the Perception APIs is available [here][docs].
## License
This library is released under the MIT license. See [LICENSE](LICENSE) for details.
[pointfreeco]: https://www.pointfree.co
[mbrandonw]: https://x.com/mbrandonw
[stephencelis]: https://x.com/stephencelis
[docs]: https://swiftpackageindex.com/pointfreeco/swift-perception/main/documentation/perception
", Assign "at most 3 tags" to the expected json: {"id":"13595","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"