At the moment I try to create a package with SwiftUI. I created a ProfileImageView. I get an Url as an optional String, which I convert to a non-optional String with if...let... In the body I use this String for an AsyncImage. The AsyncImage just needs an optional URL, so I can create the Url together with the AnsyncImage.
AsyncImage(url: URL(string: NonOptionalString)){ image in
image
}
I can just modify the image inside the asyncImage-Block so that I need some details how modified the user wants his image. So I declared a constant called modifier, which is a ViewModifier. I wanted to use it like:
image
.modifier(modifier)
So at first I declared it like this:
let modifier: ViewModifier
I got the error message "Use of protocol 'ViewModifier' as a type must be written 'any ViewModifier'" So I changed all the usages to any ViewModifier and got the error message "Type 'any ViewModifier' cannot conform to 'ViewModifier'" at this code:
AsyncImage(url: URL(string: NonOptionalString)) { image in
image
.modifier(modifier)
}
How can I fix that? Thanks!
Code:
public struct ProfileImage<Content>: View where Content: View{
let placeholder: () -> Content
let urlString: String?
let modifier: any ViewModifier
public init(_ url: String?,
@ViewBuilder placeholder: @escaping() -> Content,
modifier: any ViewModifier) {
self.placeholder = placeholder
self.urlString = url
self.modifier = modifier
}
public var body: some View{
if let NonOptionalString = urlString{
AsyncImage(url: URL(string: NonOptionalString)) { image in
image
.modifier(modifier)
// Error message: "Type 'any ViewModifier' cannot conform to 'ViewModifier'"
} placeholder: {
placeholder()
}
} else {
placeholder()
}
}
}
A possible solution is to make modifier
also generic.
And rather than Optional Binding and an extra else
clause use flatMap
to evaluate the url string
public struct ProfileImage<Content, Modifier>: View where Content: View, Modifier: ViewModifier{
let placeholder: () -> Content
let urlString: String?
let modifier: Modifier
public init(_ url: String?,
@ViewBuilder placeholder: @escaping() -> Content,
modifier: Modifier) {
self.placeholder = placeholder
self.urlString = url
self.modifier = modifier
}
public var body: some View{
AsyncImage(url: urlString.flatMap(URL.init)) { image in
image
.modifier(modifier)
} placeholder: {
placeholder()
}
}
}