diff --git a/Sources/Dependencies/DependencyValues.swift b/Sources/Dependencies/DependencyValues.swift index eda32d55..889795c3 100644 --- a/Sources/Dependencies/DependencyValues.swift +++ b/Sources/Dependencies/DependencyValues.swift @@ -268,6 +268,10 @@ public struct DependencyValues: Sendable { } set { if DependencyValues.isPreparing { + if context == .preview, Thread.isPreviewAppEntryPoint { + reportIssue("Ignoring dependencies prepared in preview app entry point") + return + } let cacheKey = CachedValues.CacheKey(id: TypeIdentifier(key), context: context) guard !cachedValues.cached.keys.contains(cacheKey) else { if cachedValues.cached[cacheKey]?.preparationID != DependencyValues.preparationID { @@ -547,6 +551,9 @@ public final class CachedValues: @unchecked Sendable { case .live: value = (key as? any DependencyKey.Type)?.liveValue as? Key.Value case .preview: + if Thread.isPreviewAppEntryPoint { + return Key.previewValue + } if !CachedValues.isAccessingCachedDependencies { value = CachedValues.$isAccessingCachedDependencies.withValue(true) { #if canImport(SwiftUI) && compiler(>=6) diff --git a/Sources/Dependencies/Internal/AppEntryPoint.swift b/Sources/Dependencies/Internal/AppEntryPoint.swift new file mode 100644 index 00000000..4b66109b --- /dev/null +++ b/Sources/Dependencies/Internal/AppEntryPoint.swift @@ -0,0 +1,30 @@ +import Foundation + +extension Thread { + public static var isPreviewAppEntryPoint: Bool { + guard ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" + else { return false } + + var isPreviewAppEntryPoint = false + for frame in callStackSymbols.reversed() { + if !isPreviewAppEntryPoint, frame.containsSymbol("$s7SwiftUI3AppPAAE4mainyyFZ") { + isPreviewAppEntryPoint = true + } else if isPreviewAppEntryPoint, + frame.containsSymbol("$s7SwiftUI6runAppys5NeverOxAA0D0RzlF") + { + return false + } + } + return isPreviewAppEntryPoint + } +} + +extension String { + fileprivate func containsSymbol(_ symbol: String) -> Bool { + utf8 + .reversed() + .drop(while: { (48...57).contains($0) }) + .dropFirst(3) + .starts(with: symbol.utf8.reversed()) + } +}