Skip to content

Commit

Permalink
Fix perception checking in computed property with geometry reader. (#45)
Browse files Browse the repository at this point in the history
* Fix perception checking in computed property with geometry reader.

* Update messaging
  • Loading branch information
mbrandonw authored Feb 29, 2024
1 parent 0236b6c commit b646ffc
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 7 deletions.
10 changes: 5 additions & 5 deletions Sources/Perception/Bindable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
/// perceptible objects.
///
/// A backport of SwiftUI's `Bindable` property wrapper.
@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)
@available(iOS, introduced: 13, obsoleted: 17, message: "Use @Bindable without the 'Perception.' prefix.")
@available(macOS, introduced: 10.15, obsoleted: 14, message: "Use @Bindable without the 'Perception.' prefix.")
@available(tvOS, introduced: 13, obsoleted: 17, message: "Use @Bindable without the 'Perception.' prefix.")
@available(watchOS, introduced: 6, obsoleted: 10, message: "Use @Bindable without the 'Perception.' prefix.")
@available(visionOS, unavailable, message: "Use @Bindable without the 'Perception.' prefix.")
@dynamicMemberLookup
@propertyWrapper
public struct Bindable<Value> {
Expand Down
15 changes: 13 additions & 2 deletions Sources/Perception/PerceptionRegistrar.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import SwiftUI

#if canImport(Observation)
import Observation
Expand Down Expand Up @@ -230,10 +231,15 @@ extension PerceptionRegistrar: Hashable {
let mangledSymbol = callStackSymbol.utf8
.drop(while: { $0 != .init(ascii: "$") })
.prefix(while: { $0 != .init(ascii: " ") })

guard let demangled = String(Substring(mangledSymbol)).demangled
else {
continue
}
if demangled.isGeometryTrailingClosure {
return true
}
guard
mangledSymbol.isMangledViewBodyGetter,
let demangled = String(Substring(mangledSymbol)).demangled,
!demangled.isSuspendingClosure,
!demangled.isActionClosure
else {
Expand All @@ -247,7 +253,12 @@ extension PerceptionRegistrar: Hashable {
}
}


extension String {
var isGeometryTrailingClosure: Bool {
self.contains("(SwiftUI.GeometryProxy) -> ")
}

fileprivate var isSuspendingClosure: Bool {
let fragment = self.utf8.drop(while: { $0 != .init(ascii: ")") }).dropFirst()
return fragment.starts(
Expand Down
45 changes: 45 additions & 0 deletions Tests/PerceptionTests/RuntimeWarningTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,51 @@
try await Task.sleep(for: .milliseconds(100))
}

func testGeometryReader_WithoutPerceptionTracking() {
struct FeatureView: View {
let model = Model()
var body: some View {
WithPerceptionTracking {
GeometryReader { _ in
Text(expectRuntimeWarning { self.model.count }.description)
}
}
}
}
self.render(FeatureView())
}

func testGeometryReader_WithProperPerceptionTracking() {
struct FeatureView: View {
let model = Model()
var body: some View {
GeometryReader { _ in
WithPerceptionTracking {
Text(self.model.count.description)
}
}
}
}
self.render(FeatureView())
}

func testGeometryReader_ComputedProperty_ImproperPerceptionTracking() {
struct FeatureView: View {
let model = Model()
var body: some View {
WithPerceptionTracking {
content
}
}
var content: some View {
GeometryReader { _ in
Text(expectRuntimeWarning { self.model.count }.description)
}
}
}
self.render(FeatureView())
}

private func render(_ view: some View) {
let image = ImageRenderer(content: view).cgImage
_ = image
Expand Down

0 comments on commit b646ffc

Please sign in to comment.