保存要在 init 之外使用的 ViewBuilder 参数
Saving ViewBuilder parameters to be used outside of init
我正在创建一个名为 AsyncImageCached 的自定义对象,使用与 AsyncImage 中相同的初始化签名。我的问题是,如何在 init 之外定义变量以保存 content 和 placeholder 当我的异步等待调用完成时要使用的参数?
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 有不同的名称)
我正在创建一个名为 AsyncImageCached 的自定义对象,使用与 AsyncImage 中相同的初始化签名。我的问题是,如何在 init 之外定义变量以保存 content 和 placeholder 当我的异步等待调用完成时要使用的参数?
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 有不同的名称)