Skip to content

Observation reference documentation #66636

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions stdlib/public/Observation/Sources/Observation/Observable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,35 @@
//===----------------------------------------------------------------------===//


/// A type that emits notifications to observers when underlying data changes.
///
/// Conforming to this protocol signals to other APIs that the type supports
/// observation. However, applying the `Observable` protocol by itself to a
/// type doesn't add observation functionality to the type. Instead, always use
/// the ``Observation/Observable-swift.macro`` macro when adding observation
/// support to a type.
@available(SwiftStdlib 5.9, *)
@_marker public protocol Observable { }

#if $Macros && hasAttribute(attached)

/// Defines and implements conformance of the Observable protocol.
///
/// This macro adds observation support to a custom type and conforms the type
/// to the ``Observation/Observable-swift.protocol`` protocol. For example, the
/// following code applies the `Observable` macro to the type `Car` making it
/// observable:
///
/// @Observable
/// class Car {
/// var name: String = ""
/// var needsRepairs: Bool = false
///
/// init(name: String, needsRepairs: Bool = false) {
/// self.name = name
/// self.needsRepairs = needsRepairs
/// }
/// }
@available(SwiftStdlib 5.9, *)
#if OBSERVATION_SUPPORTS_PEER_MACROS
@attached(member, names: named(_$observationRegistrar), named(access), named(withMutation))
Expand All @@ -26,6 +50,10 @@
public macro Observable() =
#externalMacro(module: "ObservationMacros", type: "ObservableMacro")

/// Synthesizes a property for accessors.
///
/// The ``Observation`` module uses this macro. Its use outside of the
/// framework isn't necessary.
@available(SwiftStdlib 5.9, *)
@attached(accessor, names: named(init), named(get), named(set))
#if OBSERVATION_SUPPORTS_PEER_MACROS
Expand All @@ -34,6 +62,11 @@ public macro Observable() =
public macro ObservationTracked() =
#externalMacro(module: "ObservationMacros", type: "ObservationTrackedMacro")

/// Disables observation tracking of a property.
///
/// By default, an object can observe any property of an observable type that
/// is accessible to the observing object. To prevent observation of an
/// accessible property, attach the `ObservationIgnored` macro to the property.
@available(SwiftStdlib 5.9, *)
@attached(accessor, names: named(willSet))
public macro ObservationIgnored() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
//
//===----------------------------------------------------------------------===//

/// Provides storage for tracking and access to data changes.
///
/// You don't need to create an instance of `ObservationRegistrar` when using
/// the ``Observation/Observable-swift.macro`` macro to indicate observability
/// of a type.
@available(SwiftStdlib 5.9, *)
public struct ObservationRegistrar: Sendable {
struct State: @unchecked Sendable {
Expand Down Expand Up @@ -90,9 +95,20 @@ public struct ObservationRegistrar: Sendable {

let context = Context()

/// Creates an instance of the observation registrar.
///
/// You don't need to create an instance of
/// ``Observation/ObservationRegistrar`` when using the
/// ``Observation/Observable-swift.macro`` macro to indicate observably
/// of a type.
public init() {
}

/// Registers access to a specific property for observation.
///
/// - Parameters:
/// - subject: An instance of an observable type.
/// - keyPath: The key path of an observed property.
public func access<Subject: Observable, Member>(
_ subject: Subject,
keyPath: KeyPath<Subject, Member>
Expand All @@ -106,20 +122,37 @@ public struct ObservationRegistrar: Sendable {
}
}

/// A property observation called before setting the value of the subject.
///
/// - Parameters:
/// - subject: An instance of an observable type.
/// - keyPath: The key path of an observed property.
public func willSet<Subject: Observable, Member>(
_ subject: Subject,
keyPath: KeyPath<Subject, Member>
) {
context.willSet(subject, keyPath: keyPath)
}

/// A property observation called after setting the value of the subject.
///
/// - Parameters:
/// - subject: An instance of an observable type.
/// - keyPath: The key path of an observed property.
public func didSet<Subject: Observable, Member>(
_ subject: Subject,
keyPath: KeyPath<Subject, Member>
) {

}

/// Identifies mutations to the transactions registered for observers.
///
/// This method calls ``willset(_:keypath:)`` before the mutation. Then it
/// calls ``didset(_:keypath:)`` after the mutation.
/// - Parameters:
/// - of: An instance of an observable type.
/// - keyPath: The key path of an observed property.
public func withMutation<Subject: Observable, Member, T>(
of subject: Subject,
keyPath: KeyPath<Subject, Member>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,30 @@ public struct ObservationTracking {
}
}

/// Tracks access to properties.
///
/// This method tracks access to any property within the `apply` closure, and
/// informs the caller of value changes made to participating properties by way
/// of the `onChange` closure. For example, the following code tracks changes
/// to the name of cars, but it doesn't track changes to any other property of
/// `Car`:
///
/// func render() {
/// withObservationTracking {
/// for car in cars {
/// print(car.name)
/// }
/// } onChange: {
/// print("Schedule renderer.")
/// }
/// }
///
/// - Parameters:
/// - apply: A closure that contains properties to track.
/// - onChange: The closure invoked when the value of a property changes.
///
/// - Returns: The value that the `apply` closure returns if it has a return
/// value; otherwise, there is no return value.
@available(SwiftStdlib 5.9, *)
public func withObservationTracking<T>(
_ apply: () -> T,
Expand Down