I have a protocol:
import SwiftUI
...
protocol MyProtocol : View
{
var aValue: CGFloat { get }
}
Then I have a property in a UIViewController
:
var contentView: some MyProtocol = MyView()
Where MyView
is:
struct MyView : MyProtocol
{
var aValue: CGFloat = 0.25
var body: some View
{
...
}
}
Back in my view controller I have:
func showView<V: MyProtocol>(view: V)
{
...
contentView = view // ERROR Happens here.
}
Cannot assign value of type ‘V’ to type ‘some MyProtocol’.
Why do I get this error and how can it be avoided?
2
Answers
So the type of
contentView
is "some specific, secret (opaque) type, unknown to anything but the compiler, that conforms to MyProtocol, and also happens to be exactly MyView, even though nothing can know that." It’s not "something that conforms to MyProtocol" which it seems maybe you’re thinking it is. If you mean that, the syntax is:The point of
some
is that the type is statically known at compile-time by the compiler, but not known to the caller, or by anything else.For example, even this would fail:
The compiler will not prove that MyView is exactly the secret type that
contentView
used. (For most errors of this type I’d say the compiler "cannot prove," but in this case, it’s an active decision to forbid proving the fact because that’s whatsome
does.)That "secret" type is carried along, however, and is well defined, it’s just opaque. For example, the following is fine:
At first pass, I expect the code you want is just the above
var contentView: MyProtocol
, but it’s very possible you have a deeper misunderstanding about SwiftUI. You cannot just swap in arbitrary Views in SwiftUI. As a rule, everything should be decided at compile-time, not runtime. There are tools like AnyView to work around this, but generally should not be your first choice. I expect there’s a deeper design problem here that isn’t in your question.For more details of opaque types, see SE-244.
See Rob’s answer for a good explanation of why, currently, your view controller is generic as follows and you haven’t realized it.
The property initializer you’re using only applies to one of the potentially infinite
ViewController
s that may be.