从嵌套的 Swift 包访问资产时,SwiftUI 预览会崩溃

Moj*_*ini 5 xcode swift-package-manager swiftui

一个模块

我有一个具有两个结构的模块 (A)。

  • 一种直接在代码中启动的颜色。
  • 一种从资产加载的颜色。
public struct CodeColor {
    public init() { }
    public let value = SwiftUI.Color(#colorLiteral(red: 0.8549019694, green: 0.250980407, blue: 0.4784313738, alpha: 1))
}

public struct AssetColor {
    public init() { }
    public let value = SwiftUI.Color("Legacy/Material/Gold", bundle: .module)
}
Run Code Online (Sandbox Code Playgroud)

预览效果很好:

预览


B模块

第二个模块 (B) 应使用前一个 (A) 作为依赖项从以下位置加载颜色:

import A

public struct CodeColor {
    public init() { }
    public var value: SwiftUI.Color { A.CodeColor().value }
}

public struct AssetColor {
    public init() { }
    public var value: SwiftUI.Color { A.AssetColor().value }
}
Run Code Online (Sandbox Code Playgroud)

但是一旦它触及模块 (A) 中的资产,预览就会崩溃:

B 预览

错误:

无法在此文件中预览。无法更新预览。

RemoteHumanReadableError: Failed to update preview.

The preview process appears to have crashed.

Error encountered when sending 'previewInstances' message to agent.

==================================

|  RemoteHumanReadableError: The operation couldn’t be completed. (BSServiceConnectionErrorDomain error 3.)
|  
|  BSServiceConnectionErrorDomain (3):
|  ==BSErrorCodeDescription: OperationFailed
Run Code Online (Sandbox Code Playgroud)

那是为什么?

笔记:奇怪的是,如果它在实际应用程序中(而不是另一个包),则确切的 B 预览代码正在工作

这是github上的完整代码

Luc*_*uca 3

我在开发者论坛找到了解决方案:

\n

关联

\n

https://developer.apple.com/forums/thread/664295?login=true#reply-to-this-question

\n

注意 - 本地

\n

解决方案是本地包。你定义

\n
let bundleNameIOS = "LocalPackages_TargetName"\nlet bundleNameMacOs = "PackageName_TargetName"\n
Run Code Online (Sandbox Code Playgroud)\n

REMOTE(来自 GitHub 的包,例如)

\n

如果您的包位于 GitHub 上并远程获取,则无法定义本地包,您必须将其稍微更改为:

\n
let bundleNameIOS = "TargetName_TargetName"\nlet bundleNameMacOs = "TargetName_TargetName"\n
Run Code Online (Sandbox Code Playgroud)\n

例子

\n

这是一个完整的实现示例,您必须将其与资源一起放入包中:

\n
// Inside your package with the resources:\n// Extend Bundle to access it in other packages\nextension Bundle {\n\n    // public static let assets = Bundle.module\n    // Updated with workaround\n    public static let assets = Bundle.myModule\n    \n}\n
Run Code Online (Sandbox Code Playgroud)\n

定义您的捆绑包

\n
private class CurrentBundleFinder {}\nextension Foundation.Bundle {\n    static var myModule: Bundle = {\n        /* The name of your package. You may have same PackageName and TargetName*/\n        let bundleNameIOS = "TargetName_TargetName"\n        let bundleNameMacOs = "TargetName_TargetName"\n        \n        let candidates = [\n            /* Bundle should be present here when the package is linked into an App. */\n            Bundle.main.resourceURL,\n            /* Bundle should be present here when the package is linked into a framework. */\n            Bundle(for: CurrentBundleFinder.self).resourceURL,\n            // -> Optional UI Tests\n            /* Bundle should be present here when the package is used in UI Tests. */\n            Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent(),\n            /* For command-line tools. */\n            Bundle.main.bundleURL,\n            /* Bundle should be present here when running previews from a different package (this is the path to "\xe2\x80\xa6/Debug-iphonesimulator/"). */\n            Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent(),\n            Bundle(for: CurrentBundleFinder.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent(),\n        ]\n        \n        for candidate in candidates {\n            let bundlePathiOS = candidate?.appendingPathComponent(bundleNameIOS + ".bundle")\n            let bundlePathMacOS = candidate?.appendingPathComponent(bundleNameMacOs + ".bundle")\n            if let bundle = bundlePathiOS.flatMap(Bundle.init(url:)) {\n                return bundle\n            } else if let bundle = bundlePathMacOS.flatMap(Bundle.init(url:)) {\n                return bundle\n            }\n        }\n        fatalError("unable to find bundle")\n    }()\n}\n
Run Code Online (Sandbox Code Playgroud)\n

访问包B中的包A资源

\n

您现在可以从包 B 内的包 A 访问资源,如下所示:

\n
let example = UIImage(named: "Exampe", in: Bundle.assets, with: nil)!\n
Run Code Online (Sandbox Code Playgroud)\n