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
- Use a type-erased
AnyView
:
return AnyView(Group { Text(displayName) } // AnyView type
// ...
return AnyView(Group { }) // AnyView type
- Ensure that they are the same type, by changing the empty one to:
return Group { Text("") } // Group<Text> type, same as the other one
- Return a conditional (
_ConditionalContent
) view, which ViewBuilder creates automatically when encountering anif/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
Avcapturevideodataoutput Captureoutput Not Being Called
What Would Be a Proper Storyboard Example of Combining Nav Bars and Tab Bars in One App
Unable to Save On/Off State of a Uitableviewcell
How to Disable a Constraint Programmatically
How to Cast an Any Value with Nil in It to a Any
No Value Associated with Key Codingkeys While Trying to Get Data from Github API in Xcode App
iOS - Add Image and Text in Title of Navigation Bar
Save Arfacegeometry to Obj File
Using Applescript with Apple Events in MACos - Script Not Working
How to Embed Third Party Framework on Ionic Capacitor Custom Plugin
Swiftui: How to Make Entire Shape Recognize Gestures When Stroked
Fblpromises Framework Not Found
Swift Enum Raw Value: Not Working with Cgfloat = -1.0
What's the Best Way to Iterate Over Results from an API, and Know When It's Finished
Swift 3 Optional Trouble. Can't Unwrap Url with Passed in String