This modifier on a SwiftUI view compiles fine:
.background(GeometryReader { p in
return Rectangle().opacity(0)
})
(I know I don't need the return, but I'm about to add another line.)
When I add a print
call, it no longer compiles.
.background(GeometryReader { p in
print("hi")
return Rectangle().opacity(0)
})
The error points to background
and says:
Expression type '(_, Alignment) -> some View' is ambiguous without more context
I don't understand why it's confused now about the type of thing passed to .background(...)
. It's got the same clear return
expression as before. How can I fix the code to satisfy the type checker?
This error occurs because multi-statement closures don't take part in type inference. The Content
generic parameter of the initialiser of GeometryReader
cannot be inferred because the only information you provide to it, the closure, is not considered for type-inference!
So you just need to specify what type you are returning:
.background(GeometryReader {
p -> Rectangle in // note here
print("Hello")
return Rectangle()
})
You probably shouldn't do this though, because you are supposed to only put View
s in a view builder closure. SwiftUI is designed to be very declarative, almost its own DSL, I would say.
Edit: I found this answer, which adds a View
called Print
. I guess you can put one of these alongside whatever view you are setting the background of, in a Group
.
Sorry, I edited my question just as you answered. Your answer worked, but now that I added the
.opacity
modifier, I don't know which type to use. Writingsome View
in place ofRectangle
did not cut it.@RobN This is why you shouldn't write other statements view builders. You're supposed to just write
View
s, and onlyView
s in a view builder closure. You can haveif...else
statements, but that's about all the control you have. As you probably found out already, you practically can't declare variables, or do a for/while loop in a view builder, same goes forprint
.Okay, I can adapt that
Print
view to my needs. The original design proposal for function builders, linked off the Swift forum (forums.swift.org/t/function-builders/25167) had more things allowed, like local variables. So I think some of these restrictions are just that it's currently all half implemented.Well, it's not that you physically can't write variable declarations. I said "practically can't", because whenever you do, the closure gets ignored in type inference. The type might still be abled to be inferred by other means, but because of the contexts in which view builders are usually used (opaque return type), type inference almost always fails.