Implicit Return in a Closure Causing an Error

implicit return in a closure causing an error

Not sure how to handle the above without having to have the dummy return statement, any advise.

You have solved the problem beautifully. Anonymous functions automatically use a one-line function body as a return value, so to prevent that from causing a type mismatch with the expected return type (Void) you have to add another line of code so that it is not a one-line function body. The dummy return statement, which itself returns Void, is a great way to handle it; I would just use that and move on. There are some snazzier workarounds but what you have is precisely what I would do.

EDIT: To understand the source of the type mismatch, try this:

struct Test {
func voider() -> Void {}
}

let testMaybe = Optional(Test())
let result = testMaybe?.voider()

Now result is not a Void; it's an Optional wrapping a Void. That is what's happening to you; a Void is expected but your one-line anonymous function returns an Optional wrapping a Void. By adding another line that returns Void explicitly, you solved the problem.

How to Supress implicit return from a closure with Void return type in Swift

I recreated your example with your code (with minor tweaks) and didn't have the problem you described. I used a swift dictionary instead though, since I have no knowledge about Obj-C.

func doSomething(completionHandler: Bool -> Void) {
completionHandler(true)
}

doSomething() { finished in
var data = [String: String]()
data.updateValue("data1", forKey: "data1") // 1
data.updateValue("data2", forKey: "data2") // 2
data.updateValue("data3", forKey: "data3") // 3

for (key, value) in data {
println("Key: \(key) & Value: \(value)")
}
}

The output is:

Key: data2 & Value: data2
Key: data1 & Value: data1 // Not sure why data1 is second here
Key: data3 & Value: data3

I doubt using NSDictionary could be the cause of it, maybe something else is causing it to return?

Why can't returns infer the type of the return, and I have to explicitly return instead of using closures?

Let's understand your code to more clearly see what happens.

pub fn bigger(a: i32, b: i32) -> i32 {
let biggest = if a > b { a } else { return b };
}

You're creating a locally-scoped binding with the name biggest. If a > b it will have value of a, else the function will return b.

So for a > b there is no implicit or explicit return value for this function.

In this function, there is no need for an explicitly named biggest binding. You can use Rust's property of implicit returns:

pub fn bigger(a: i32, b: i32) -> i32 {
if a > b {
a
} else {
b
}
}

I should mention that this function is equivalent to std::cmp::max from the standard library.

Statement in SwiftUI closure body causes type error

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 Views 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.

Declare a temporary variable or constant inside a closure that returns some View (SwiftUI)

This is due to a limitation where the Swift compiler only tries to infer a closure's return type if it is a single expression. Closure's that are processed by a result builder, such as @ViewBuilder, are not subject to this limitation. Importantly, this limitation also doesn't affect functions (only closures).

I was able to make this work by moving the closure to a method inside the structure. Note: this is the same as @cluelessCoder's second solution, just excluding the @ViewBuilder attribute.

struct GameView: View {
@State private var cards = [
Card(value: 100),
Card(value: 20),
Card(value: 80),
]

var body: some View {
MyListView(items: cards, content: cardView)
}

func cardView(for card: Card) -> some View {
let label = label(for: card) // only called once, and can be reused.
return Text(label)
}

func label(for card: Card) -> String {
return "Card with value \(card.value)"
}
}

Thanks to @cluelessCoder. I would have never stumbled upon this discovery without their input and helpful answer.



Related Topics



Leave a reply



Submit