Skip to content

Commit b646ffc

Browse files
authored
Fix perception checking in computed property with geometry reader. (pointfreeco#45)
* Fix perception checking in computed property with geometry reader. * Update messaging
1 parent 0236b6c commit b646ffc

File tree

3 files changed

+63
-7
lines changed

3 files changed

+63
-7
lines changed

Sources/Perception/Bindable.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
/// perceptible objects.
66
///
77
/// A backport of SwiftUI's `Bindable` property wrapper.
8-
@available(iOS, introduced: 13, obsoleted: 17)
9-
@available(macOS, introduced: 10.15, obsoleted: 14)
10-
@available(tvOS, introduced: 13, obsoleted: 17)
11-
@available(watchOS, introduced: 6, obsoleted: 10)
12-
@available(visionOS, unavailable)
8+
@available(iOS, introduced: 13, obsoleted: 17, message: "Use @Bindable without the 'Perception.' prefix.")
9+
@available(macOS, introduced: 10.15, obsoleted: 14, message: "Use @Bindable without the 'Perception.' prefix.")
10+
@available(tvOS, introduced: 13, obsoleted: 17, message: "Use @Bindable without the 'Perception.' prefix.")
11+
@available(watchOS, introduced: 6, obsoleted: 10, message: "Use @Bindable without the 'Perception.' prefix.")
12+
@available(visionOS, unavailable, message: "Use @Bindable without the 'Perception.' prefix.")
1313
@dynamicMemberLookup
1414
@propertyWrapper
1515
public struct Bindable<Value> {

Sources/Perception/PerceptionRegistrar.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Foundation
2+
import SwiftUI
23

34
#if canImport(Observation)
45
import Observation
@@ -230,10 +231,15 @@ extension PerceptionRegistrar: Hashable {
230231
let mangledSymbol = callStackSymbol.utf8
231232
.drop(while: { $0 != .init(ascii: "$") })
232233
.prefix(while: { $0 != .init(ascii: " ") })
233-
234+
guard let demangled = String(Substring(mangledSymbol)).demangled
235+
else {
236+
continue
237+
}
238+
if demangled.isGeometryTrailingClosure {
239+
return true
240+
}
234241
guard
235242
mangledSymbol.isMangledViewBodyGetter,
236-
let demangled = String(Substring(mangledSymbol)).demangled,
237243
!demangled.isSuspendingClosure,
238244
!demangled.isActionClosure
239245
else {
@@ -247,7 +253,12 @@ extension PerceptionRegistrar: Hashable {
247253
}
248254
}
249255

256+
250257
extension String {
258+
var isGeometryTrailingClosure: Bool {
259+
self.contains("(SwiftUI.GeometryProxy) -> ")
260+
}
261+
251262
fileprivate var isSuspendingClosure: Bool {
252263
let fragment = self.utf8.drop(while: { $0 != .init(ascii: ")") }).dropFirst()
253264
return fragment.starts(

Tests/PerceptionTests/RuntimeWarningTests.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,51 @@
499499
try await Task.sleep(for: .milliseconds(100))
500500
}
501501

502+
func testGeometryReader_WithoutPerceptionTracking() {
503+
struct FeatureView: View {
504+
let model = Model()
505+
var body: some View {
506+
WithPerceptionTracking {
507+
GeometryReader { _ in
508+
Text(expectRuntimeWarning { self.model.count }.description)
509+
}
510+
}
511+
}
512+
}
513+
self.render(FeatureView())
514+
}
515+
516+
func testGeometryReader_WithProperPerceptionTracking() {
517+
struct FeatureView: View {
518+
let model = Model()
519+
var body: some View {
520+
GeometryReader { _ in
521+
WithPerceptionTracking {
522+
Text(self.model.count.description)
523+
}
524+
}
525+
}
526+
}
527+
self.render(FeatureView())
528+
}
529+
530+
func testGeometryReader_ComputedProperty_ImproperPerceptionTracking() {
531+
struct FeatureView: View {
532+
let model = Model()
533+
var body: some View {
534+
WithPerceptionTracking {
535+
content
536+
}
537+
}
538+
var content: some View {
539+
GeometryReader { _ in
540+
Text(expectRuntimeWarning { self.model.count }.description)
541+
}
542+
}
543+
}
544+
self.render(FeatureView())
545+
}
546+
502547
private func render(_ view: some View) {
503548
let image = ImageRenderer(content: view).cgImage
504549
_ = image

0 commit comments

Comments
 (0)