File tree Expand file tree Collapse file tree 2 files changed +15
-10
lines changed Expand file tree Collapse file tree 2 files changed +15
-10
lines changed Original file line number Diff line number Diff line change @@ -26,6 +26,14 @@ extension View {
2626 /// - scope: Optionally overrides the view's default scope of introspection.
2727 /// - customize: A closure that hands over the underlying UIKit/AppKit instance ready for customization.
2828 ///
29+ /// Note there is no guarantee of one-time execution for this closure. As `customize` may fire multiple times,
30+ /// make sure to guard against repeated or heavy work in your closure by keeping track of its completeness.
31+ ///
32+ /// Additionally, note mutating SwiftUI state within `customize` will trigger runtime warnings unless that mutation
33+ /// is wrapped in a `DispatchQueue.main.async { ... }` call. This is because introspect attempts to hand you
34+ /// the requested view as soon as possible, and this might mean SwiftUI isn't ready for state mutations at that
35+ /// particular moment.
36+ ///
2937 /// Here's an example usage:
3038 ///
3139 /// ```swift
Original file line number Diff line number Diff line change @@ -121,15 +121,6 @@ struct IntrospectionView<Target: PlatformEntity>: PlatformViewControllerRepresen
121121 customize ( target)
122122 controller. handler = nil
123123 }
124-
125- // - Workaround -
126- // iOS/tvOS 13 sometimes need a nudge on the next run loop.
127- if #available( iOS 14 , tvOS 14 , * ) { } else {
128- DispatchQueue . main. async { [ weak controller] in
129- controller? . handler ? ( )
130- }
131- }
132-
133124 return controller
134125 }
135126
@@ -159,7 +150,13 @@ final class IntrospectionPlatformViewController: PlatformViewController {
159150 guard let self else {
160151 return
161152 }
162- handler ? ( self )
153+
154+ // NB: .introspect makes no guarantees about the number of times its callback is invoked,
155+ // so the below is fair play to maximize compatibility and predictability
156+ handler ? ( self ) // we call this eagerly as most customization can successfully happen without a thread hop
157+ DispatchQueue . main. async {
158+ handler ? ( self ) // we also thread hop to cover the rest of the cases where the underlying UI component isn't quite ready for customization
159+ }
163160 }
164161 self . isIntrospectionPlatformEntity = true
165162 IntrospectionStore . shared [ id, default: . init( ) ] . controller = self
You can’t perform that action at this time.
0 commit comments