Skip to content

Commit

Permalink
Add support for SwiftUI environment
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Jan 12, 2024
1 parent 14ac2d3 commit bdd0b91
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
11 changes: 9 additions & 2 deletions Example/Example/ExampleApp.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import SwiftUI
import Perception

@main
struct ExampleApp: App {
let model = CounterModel()

var body: some Scene {
WindowGroup {
ContentView(model: CounterModel())
WithPerceptionTracking {
let _ = print("!!!")
// let _ = model.count
WindowGroup {
ContentView(model: model)
}
}
}
}
62 changes: 62 additions & 0 deletions Sources/Perception/Environment.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import SwiftUI

extension Environment {
@available(iOS, introduced: 13, obsoleted: 17)
@available(macOS, introduced: 10.15, obsoleted: 14)
@available(tvOS, introduced: 13, obsoleted: 17)
@available(watchOS, introduced: 6, obsoleted: 10)
@available(visionOS, unavailable)
@_disfavoredOverload
public init(_ objectType: Value.Type) where Value: AnyObject & Perceptible {
self.init(\.[unwrap: \Value.self])
}

@available(iOS, introduced: 13, obsoleted: 17)
@available(macOS, introduced: 10.15, obsoleted: 14)
@available(tvOS, introduced: 13, obsoleted: 17)
@available(watchOS, introduced: 6, obsoleted: 10)
@available(visionOS, unavailable)
@_disfavoredOverload
public init<T: AnyObject & Perceptible>(_ objectType: T.Type) where Value == T? {
self.init(\.[\T.self])
}
}

extension View {
@available(iOS, introduced: 13, obsoleted: 17)
@available(macOS, introduced: 10.15, obsoleted: 14)
@available(tvOS, introduced: 13, obsoleted: 17)
@available(watchOS, introduced: 6, obsoleted: 10)
@available(visionOS, unavailable)
public func environment<T: AnyObject & Perceptible>(_ object: T?) -> some View {
self.environment(\.[\T.self], object)
}
}

private struct PerceptibleKey<T: Perceptible>: EnvironmentKey {
static var defaultValue: T? { nil }
}

extension EnvironmentValues {
fileprivate subscript<T: Perceptible>(_: KeyPath<T, T>) -> T? {
get { self[PerceptibleKey<T>.self] }
set { self[PerceptibleKey<T>.self] = newValue }
}
}

extension EnvironmentValues {
fileprivate subscript<T: Perceptible>(unwrap _: KeyPath<T, T>) -> T {
get {
guard let object = self[\T.self] else {
fatalError(
"""
No perceptible object of type \(T.self) found. A View.environment(_:) for \(T.self) may \
be missing as an ancestor of this view.
"""
)
}
return object
}
set { self[\T.self] = newValue }
}
}

0 comments on commit bdd0b91

Please sign in to comment.