Skip to content
Open
Show file tree
Hide file tree
Changes from 8 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
62 changes: 57 additions & 5 deletions Sources/SwiftNavigation/NSObject+Observe.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
/// any accessed fields so that the view is always up-to-date.
///
/// It is most useful when dealing with non-SwiftUI views, such as UIKit views and controller.
/// You can invoke the ``observe(_:)`` method a single time in the `viewDidLoad` and update all
/// You can invoke the ``observe(_:)-(()->Void)`` method a single time in the `viewDidLoad` and update all
/// the view elements:
///
/// ```swift
Expand All @@ -37,7 +37,7 @@
/// ever mutated, this trailing closure will be called again, allowing us to update the view
/// again.
///
/// Generally speaking you can usually have a single ``observe(_:)`` in the entry point of your
/// Generally speaking you can usually have a single ``observe(_:)-(()->Void)`` in the entry point of your
/// view, such as `viewDidLoad` for `UIViewController`. This works even if you have many UI
/// components to update:
///
Expand All @@ -64,7 +64,7 @@
/// a label or the `isHidden` of a button.
///
/// However, if there is heavy work you need to perform when state changes, then it is best to
/// put that in its own ``observe(_:)``. For example, if you needed to reload a table view or
/// put that in its own ``observe(_:)-(()->Void)``. For example, if you needed to reload a table view or
/// collection view when a collection changes:
///
/// ```swift
Expand Down Expand Up @@ -106,13 +106,36 @@
/// of a property changes.
/// - Returns: A cancellation token.
@discardableResult
public func observe(_ apply: @escaping @MainActor @Sendable () -> Void) -> ObserveToken {
public func observe(
_ apply: @escaping @MainActor @Sendable () -> Void
) -> ObserveToken {
observe { _ in apply() }
}

/// Observe access to properties of an observable (or perceptible) object.
///
/// A version of ``observe(_:)`` that is passed the current transaction.
/// This tool allows you to set up an observation loop so that you can access fields from an
/// observable model in order to populate your view, and also automatically track changes to
/// any fields accessed in the tracking parameter so that the view is always up-to-date.
///
/// - Parameter tracking: A closure that contains properties to track

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// - Parameter tracking: A closure that contains properties to track
/// - Parameter context: A closure that contains properties to track

/// - Parameter onChange: Invoked when the value of a property changes
/// - Returns: A cancellation token.
@discardableResult
public func observe(
_ context: @escaping @MainActor @Sendable () -> Void,
onChange apply: @escaping @MainActor @Sendable () -> Void
) -> ObserveToken {
observe { _ in
context()
} onChange: { _ in
apply()
}
}

/// Observe access to properties of an observable (or perceptible) object.
///
/// A version of ``observe(_:)-(()->Void)`` that is passed the current transaction.
///
/// - Parameter apply: A closure that contains properties to track and is invoked when the value
/// of a property changes.
Expand All @@ -134,6 +157,35 @@
return token
}

/// Observe access to properties of an observable (or perceptible) object.
///
/// A version of ``observe(_:onChange:)-(()->Void,_)`` that is passed the current transaction.
///
/// - Parameter tracking: A closure that contains properties to track
/// - Parameter onChange: Invoked when the value of a property changes
/// - Returns: A cancellation token.
@discardableResult
public func observe(
_ context: @escaping @MainActor @Sendable (_ transaction: UITransaction) -> Void,
onChange apply: @escaping @MainActor @Sendable (_ transaction: UITransaction) -> Void
) -> ObserveToken {
let token = SwiftNavigation._observe { transaction in
MainActor._assumeIsolated {
context(transaction)
}
} onChange: { transaction in
MainActor._assumeIsolated {
apply(transaction)
}
} task: { transaction, work in
DispatchQueue.main.async {
withUITransaction(transaction, work)
}
}
tokens.append(token)
return token
}

fileprivate var tokens: [Any] {
get {
objc_getAssociatedObject(self, Self.tokensKey) as? [Any] ?? []
Expand Down
Loading
Loading