Error message: "Type 'any ViewModifier' cannot conform to 'ViewModifier'"

433 Views Asked by At

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()
        }
    }
}
1

There are 1 best solutions below

1
On BEST ANSWER

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()
        }
    }
}