Swift Closure Type Inference

Infer closure return type from closure body when working with generics

Actually, it seems that I was pushing the compiler limits too hard (as @Martin R pointed in the comments). The { a in } closure was kinda incomplete, since the compiler had no statements to infer the closure return type from.

This works:

Test<Int>().test { (a: Int) -> Void in () }

Same as the following:

func doNothing() { }

Test<Int>().test { (a: Int) -> Void in doNothing() }

In the above examples the compiler is provided with the minimum amount of information to determine which overload to pick.

How can I solve Unable to infer type of a closure parameter issue?

Generics parameter (T in your case) is input, so you should give on input of function all arguments typed (compiler does not jump inside to cycle through implementation to find where the type could be)

So the solution is to provide explicit type in closure, like

testValue(value: { (newValue: Bool) in      // << here !!

bool = newValue // <<: This or That!

print(newValue) // <<: This or That!

})

Tested with Xcode 13.1 / iOS 15

Update: You can keep T in function and use it inside as input argument for processing, like

func testValue<T>(value: @escaping (T) -> Void) {
if T.self == Bool.self {
let randomValue: Bool = true
value(randomValue as! T)
} else if T.self == String.self {
let randomValue: String = "Test"
value(randomValue as! T)
}
}

struct ContentView: View {
@State private var bool: Bool = Bool()

var body: some View {

Text("Hello, World!")
.onAppear() {
testValue(value: { (newValue: Bool) in
bool = newValue
print(newValue)
})
testValue(value: { (newValue: String) in
print("Got: \(newValue)")
})
}
}
}

Sample Image

Swift inferred closure parameter puzzle

It is ambiguous. Both .times() methods can be used with the given closure expression if the parameter type of the closure is not known.

If you just write { i in println("Year \(i)") }, it is just a closure that takes one parameter of any type. Well, EVERY function type in Swift can be viewed as taking one parameter:

  • What you think of as zero-parameter functions actually take one parameter of type () (a.k.a. Void), of value (), that's why the type is written as () -> something
  • What you think of as multiple-parameter functions actually take one parameter of tuple type, a tuple of all the "multiple arguments", that's why the type is written as (foo, bar) -> something.

So, basically, your closure expression, without specifying the type of i, can be inferred to ANY function type in Swift that returns Void. The functions taken by both .times() methods match this -- for the first .times() method, it is inferred as a function of type () -> (), i.e. i has type (); for the second .times() method, it is inferred as a function of type Int -> (), i.e. i has type Int.

Unable to infer closure type in the current context

The reason why it is not inferring the closure type is because the try statement is not handled. This means that the closure expected to "catch" the error, but in your case, you forgot the do-try-catch rule.

Therefore you can try the following answer which will catch your errors:

do {
let imageAsData = try Data(contentsOf: imageURL)
let image = UIImage(data: imageAsData)
let ImageObject = Image()
ImageObject.image = image
self.arrayOfImgObj.append(ImageObject)
} catch {
print("imageURL was not able to be converted into data") // Assert or add an alert
}

You can then assert an error (for testing), or what I would personally do, is set up an alert.

This way the app wouldn't crash, but instead, notify the user. I find this very helpful when on the go and my device isn't plugged in - so I can see the error messages instead of a blank crash with no idea what happened.

Adding inline explicit type annotations to a closure with a return value but no input parameters in Swift?

The empty tuple () indicates an empty argument list:

let f = { () -> Double in
1 + 1
}

print(f()) // 2.0

() can be both a type (identical to Void) and an instance of that type:

let a: Void = ()
let b: () = ()
print(type(of: a) == type(of: b)) // true

Swift is unable to type infer variable containing closure that returns Bool

Swift can currently infer only single-return closures. You can rewrite your closure to:

let downloadNextPagination = { 
return current.integerValue < amount.integerValue && current.integerValue != amount.integerValue - 1
}


Related Topics



Leave a reply



Submit