Swiftui: Function Declares an Opaque Return Type, But the Return Statements in Its Body Do Not Have Matching Underlying Types

SwiftUI: Function declares an opaque return type, but the return statements in its body do not have matching underlying types

You need to use @ViewBuilder in this case (and remove returns, because return disables ViewBuilder)

struct NavigationViewManager {
@ViewBuilder
static func make<V: View>(_ kind: NavigationViewKind, _ contentView: @escaping () -> V) -> some View {
switch kind {
case .test1(let text):
NavigationView {
contentView()
.navigationBarTitle(text, displayMode: .inline)
}
case .test2:
NavigationView {
contentView()
.navigationBarTitle("Initial", displayMode: .large)
}
}
}
}

For SwiftUI Gestures: Function declares an opaque return type, but the return statements in its body do not have matching underlying types

Assuming that not provided zoomGesture has same value as magnification gesture (otherwise it would not be operable in any case) the fixed variant can be as follows

private func pinchGesture() -> AnyGesture<CGFloat> {
if selectedEmojis.count == 0 {
return AnyGesture(zoomGesture())
} else {
return AnyGesture(MagnificationGesture()
.updating($emojiZoomScale) { latestGestureScale, emojiZoomScale, _ in
emojiZoomScale = latestGestureScale
}
.onEnded { gestureScaleAtEnd in
steadyStateEmojiZoomScale *= gestureScaleAtEnd
})
}
}

alternate is to break this on two separated gesture properties and use condition within view hierarchy to have advantage of ViewBuilder

How to fix the error Function declares an opaque return type, but the return statements in its body do not have matching underlying types ?

body in a SwiftUI is a ViewBuilder (which is a type of ResultBuilder), which has some special properties. To take advantage of it, you'll want to remove your explicit return statements and let it return a view hierarchy implicitly instead:

var body: some View {
if let image = self.imageLoader.downloadImage {
Image(uiImage: image) //<-- This gets returned
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 55, height: 60, alignment: .center)
} else {
placeholder //<-- or, this gets returned
}
}

Function declares an opaque return type [...] error when declaring a view as a variable inside the body of a View in SwiftUI

When modifying and building views, you can do this without a return statement and a building block one above the other without commas. This is called a multi-statement closure. When you try to create a variable inside a multi-statement closure, the compiler is going to complain because there is a mismatch in types (you can only combine views one after another, nothing more). See this answer for more details: https://stackoverflow.com/a/56435128/7715250

A way to fix this is to explicitly return the views you are combining, so you don't make use of the multi-closure statements:

struct MyView: View {
var body: some View {
let image = Image("Some image").shadow(radius: 10)
let myRadius = image.modifier.radius

// Do something with myRadius

return image // No multi closure statements.
}
}

How to make a function returning some Gesture or SimultaneousGesture properly?

When you use an "opaque return type" (like some Gesture), you are asserting to the compiler that you will only return 1 specific concrete Gesture type, you just don't want to write out its full signature.
This is why you cannot dynamically return different types at runtime.
This is why the ternary operator (?:) is failing as well; a ternary operator only accepts operands of the same type.

A workaround is use a SwiftUI ViewBuilder to let the SwiftUI runtime activate the correct gesture on the view based on the condition.

var baseView: some View {
Text("123")
}

@ViewBuilder
var content: some View {
if someCondition {
baseView
.gesture(makeGesture1())
} else {
baseView
.gesture(makeGesture1().simultaneously(with: makeGesture2()))
}
}

This is allowed as internally SwiftUI is using something called a "result builder" to only return 1 branch of the if statement at runtime, with each branch of the if statement having a concrete type.

In SwiftUI, avoid using any of the type erased wrappers (AnyView, AnyGesture etc.) as they increase the computational overhead on SwiftUI.

Group() not recognized as an opaque type in SwiftUI

Opaque types still require there to be a concrete single type specified by a callee, but in your function you have two different return types:

return Group { Text(displayName) } // Group<Text> type
// and also
return Group { } // Group<EmptyView> type

So, you need to either

  1. Use a type-erased AnyView:
return AnyView(Group { Text(displayName) }  // AnyView type
// ...
return AnyView(Group { }) // AnyView type

  1. Ensure that they are the same type, by changing the empty one to:
return Group { Text("") }  // Group<Text> type, same as the other one

  1. Return a conditional (_ConditionalContent) view, which ViewBuilder creates automatically when encountering an if/else:
@ViewBuilder // this is required
func cellWithContact(_ contact: CNContact) -> some View {
// ...
if someCondition { // _ConditionalContent<Group<Text>, Group<EmptyView>> type
Group { Text(...) }
} else {
Group { }
}
}


Related Topics



Leave a reply



Submit