保存要在 init 之外使用的 ViewBuilder 参数

Saving ViewBuilder parameters to be used outside of init

我正在创建一个名为 AsyncImageCached 的自定义对象,使用与 AsyncImage 中相同的初始化签名。我的问题是,如何在 init 之外定义变量以保存 contentplaceholder 当我的异步等待调用完成时要使用的参数?

public struct AsyncImageCached<Content> : View where Content : View {

    private let content: ((Image) -> I)?   <--- Doesn't Work, Cannot find type 'I' in scope
    private let placeholder: (() -> P)?    <--- Doesn't work, Cannot find type 'P' in scope

    init<I, P>(url: URL?, scale: CGFloat = 1, 
        @ViewBuilder content: @escaping (Image) -> I,
        @ViewBuilder placeholder: @escaping () -> P)
        where Content == _ConditionalContent<I, P>, I : View, P : View {

        let content: (Image) -> I = content    <--- Works, but can't access outside of init
        let placeholder: () -> P = placeholder <--- Works, but can't access outside of init

        ...
    }
}

将 I、P 移动到结构级别会破坏其他 init,并且不会匹配 Apple 的 AsyncImage 签名。

一定有办法让它工作,因为 AsyncImage 中有相同的签名。我不想更改 init 签名函数,因为我已经让其他 inits 工作了:

public init(url: URL?, scale: CGFloat = 1) where Content == Image
public init(url: URL?, scale: CGFloat = 1, @ViewBuilder content: @escaping (AsyncImagePhase) -> Content)

任何帮助将不胜感激,我在这上面花了两天时间,但我在网上找不到任何教导如何在简单示例之外使用 ViewBuilder 的内容,没有像这样的自定义初始化。

嗯,检查Swift接口文件,我们可以看到如下内容:

public struct AsyncImage<Content> : SwiftUI.View where Content : SwiftUI.View {
    /* ... */

    @_alwaysEmitIntoClient public init<I, P>(url: Foundation.URL?, scale: CoreGraphics.CGFloat = 1, @SwiftUI.ViewBuilder content: @escaping (SwiftUI.Image) -> I, @SwiftUI.ViewBuilder placeholder: @escaping () -> P) where Content == SwiftUI._ConditionalContent<I, P>, I : SwiftUI.View, P : SwiftUI.View {
        self.init(url: url, scale: scale) { phase in
            if let i = phase.image {
                content(i)
            } else {
                placeholder()
            }
        }
    }

    /* ... */
}

所以,事实证明它只是调用另一个 init 本身,不需要这些泛型!

您可以在 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SwiftUI.framework/Modules/SwiftUI.swiftmodule/arm64.swiftinterface 看到接口文件,将 Xcode.app 替换为任何名称(因为 beta 有不同的名称)