I'm creating a custom object called AsyncImageCached using the same init signature as found in AsyncImage. My question is, how do I define variables outside of init to save content and placeholder parameters to be used when my async await calls complete?
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
...
}
}
Moving I, P to the structure level will break the other inits and will not match Apples AsyncImage signatures.
There must be a way to make it work because the same signature is in AsyncImage. I don't want to change the init signature function because I already have the other inits working:
public init(url: URL?, scale: CGFloat = 1) where Content == Image
public init(url: URL?, scale: CGFloat = 1, @ViewBuilder content: @escaping (AsyncImagePhase) -> Content)
Any help would be greatly appreciated, I have spent two days on this and I can't find anything online that teaches how to use the ViewBuilder outside of simple examples, non that have a custom init like this.
Well, inspecting Swift interface file, we can see the following:
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()
}
}
}
/* ... */
}
So, it turns out it just calls another init
itself, which doesn't require these generics!
You can see the interface file at /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/System/Library/Frameworks/SwiftUI.framework/Modules/SwiftUI.swiftmodule/arm64.swiftinterface
, replacing Xcode.app
with whatever the name is (as betas have different names)