Swift - Optional Void
This is simply because you are using Optional Chaining. The method returns Void
, but it is possible for the whole chain to return nil
before the method is ever called.
Essentially, a return value of Void
will mean the call was actually made (self and client both have values) while a nil
result will mean that one of those were nil
.
Swift optional completion handler
Completion handlers are similar to function return
values, but not the same. For example, compare the following functions:
/// 1. With return value
func createList(name: String) -> Response { }
/// 2. With completion handler
func createList(name: String, completion: @escaping (Response) -> Void) { }
In the first function, you'd get the return value instantly.
let response = barback.createList(name: name)
if response.status = 200 {
/// trigger some UI component
}
However, if you try the same for the second function, you'll get the Missing argument for parameter 'completion' in call
error. That's because, well, you defined a completion:
argument label. However, you didn't supply it, as matt commented.
Think of completion handlers as "passing in" a chunk of code into the function, as a parameter. You need to supply that chunk of code. And from within that chunk of code, you can access your Response
.
/// pass in chunk of code here
barback.createList(name: name, completion: { response in
/// access `response` from within block of code
if response.status = 200 {
/// trigger some UI component
}
})
Note how you just say barback.createList
, not let result = barback.createList
. That's because in the second function, with the completion handler, doesn't have a return value (-> Response
).
Swift also has a nice feature called trailing closure syntax, which lets you omit the argument label completion:
.
barback.createList(name: name) { response in
/// access `response` from within block of code
if response.status = 200 {
/// trigger some UI component
}
}
You can also refer to response
, the closure's first argument, by using $0
(which was what I did in my comment). But whether you use $0
or supply a custom name like response
is up to you, sometimes $0
is just easier to type out.
barback.createList(name: name) {
/// access $0 (`response`) from within block of code
if $0.status = 200 {
/// trigger some UI component
}
}
Passing optional closure to the View
Change your variable let to var.
var action: (() -> Void)? = nil
Swift optional escaping closure parameter
There is a SR-2552 reporting that @escaping
is not recognizing function type alias. that's why the error @escaping attribute only applies to function types
. you can workaround by expanding the function type in the function signature:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: (@escaping ()->())?) {
print(stuff)
action = completion
completion?()
}
func doStuffAgain() {
print("again")
action?()
}
doStuff(stuff: "do stuff") {
print("swift 3!")
}
doStuffAgain()
EDIT 1::
I was actually under a xcode 8 beta version where the bug SR-2552 was not resolved yet. fixing that bug, introduced a new one(the one you're facing) that is still open. see SR-2444.
The workaround @Michael Ilseman pointed as a temporary solution is remove the @escaping
attribute from optional function type, that keep the function as escaping.
func doStuff(stuff: String, completion: Action?) {...}
EDIT 2::
The SR-2444 has been closed stating explicitly that closures in parameters positions are not escaping and need them to be marked with @escaping
to make them escaping, but the optional parameters are implicitly escaping, since ((Int)->())?
is a synonyms of Optional<(Int)->()>
, optional closures are escaping.
Why its impossible to cast `(()-Void)` to `(()-Void)?`
When a closure is wrapped inside an optional, that closure "escapes". If you don't know what "escapes" means, read this answer of mine.
The non-optional closure in the second getData
, however, is not @escaping
. So you are trying to make a non-escaping closure escape! The error message is kind of confusing here, but if you pass .some(callback)
rather than callback
directly, it becomes clear what's happening:
Converting non-escaping parameter 'callback' to generic parameter 'Wrapped' may allow it to escape
So you should mark callback
in your second getData
as @escaping
:
func getData(id: CLong, callback: @escaping ((Dictionary<String, Any>) -> Void) ) {
Optional try for function with no return value
There is no reason for the compiler to complain. The return type
of
func throwingVoidFunction() throws { ... }
is Void
and therefore the type of the expression
try? throwingVoidFunction()
is Optional<Void>
, and its value is nil
(== Optional<Void>.none
) if an error was thrown while evaluating the expression,
and Optional<Void>.some()
otherwise.
You can ignore the return value or test it against nil
. An
example is given in An elegant way to ignore any errors thrown by a method:
let fileURL = URL(fileURLWithPath: "/path/to/file")
let fm = FileManager.default
try? fm.removeItem(at: fileURL)
Swift optional escaping closure
Clarification:
For understanding the case, implementing the following code would be useful:
typealias completion = () -> ()
enum CompletionHandler {
case success
case failure
static var handler: completion {
get { return { } }
set { }
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler.handler = handlerParameter
}
At the first look, this code seems to be legal, but it's not! you would get compile-time error complaining:
error: assigning non-escaping
parameter 'handlerParameter' to an @escaping closurelet chObject = CompletionHandler.handler = handlerParameter
with a note that:
note: parameter 'handlerParameter' is implicitly non-escaping func
doSomething(handlerParameter: completion) {
Why is that? the assumption is that the code snippet has nothing to do with the @escaping
...
Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum, struct or class by default.
As a reference, there are bugs reported related to this issue:
- Optional closure type is always considered @escaping.
- @escaping failing on optional blocks.
Although they might not 100% related to this case, the assignee comments are clearly describe the case:
First comment:
The actual issue here is that optional closures are implicitly
@escaping right now.
Second comment:
That is unfortunately the case for Swift 3. Here are the semantics for
escaping in Swift 3:1) Closures in function parameter position are
non-escaping by default2) All other closures are escaping
Thus, all generic type argument closures, such as Array and Optional, are escaping.
Obviously, Optional
is enum.
Also -as mentioned above-, the same behavior would be applicable for the classes and structs:
Class Case:
typealias completion = () -> ()
class CompletionHandler {
var handler: () -> ()
init(handler: () -> ()) {
self.handler = handler
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
Struct Case:
typealias completion = () -> ()
struct CompletionHandler {
var handler: completion
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
The two above code snippets would leads to the same output (compile-time error).
For fixing the case, you would need to let the function signature to be:
func doSomething( handlerParameter: @escaping completion)
Back to the Main Question:
Since you are expecting that you have to let the completion:(()->())?
to be escaped, that would automatically done -as described above-.
Is optional closure always escaping? Should we use [weak self] or [unowned self] on it?
According to the compiler (which has the only "opinion" that matters for something like this), an optional closure parameter is always implicitly @escaping
. Test this yourself by writing a function that takes an optional closure and mark it as @escaping
. The compiler will inform you that it's already escaping.
As to whether you should capture self
as weak
or unowned
, that depends. First I'd stay away from capturing self
as unowned
, unless you want your program to crash if you're wrong about the lifetime of self
- and you might. I'd rather my program crash than silently do the wrong thing.
But that leaves whether to capture as weak
. My opinion is yes, if you're in any doubt capturing a strong reference creating a reference cycle that would prevent it from properly deinitializing. But I wouldn't go so far as to say always or never do something. If you are able to reason about your object's life time so that you know the closure will be run and disposed of before the object should normally be deinitialized, then just capture as a strong reference. Also capture by strong reference if you purposefully want to extend the life of your object for the sake of the closure and you know that the closure will be executed and disposed of.
Also there is the case where you know that despite being implicitly @escaping
that it doesn't actually escape. Usually that's for a function defined in your code base so you can look at the implementation, but really any time the closure is just a customization point for work that has to be done before the function you're calling returns, you can infer that it doesn't actually escape. That's not the case for completion handlers, but it might be for other things.
That's my opinion. I like to think it's an informed one, but others might disagree.
Swift optional promotion vs generic overload resolution
Specificity seems to always trump variance conversions, according to my experiments. For example:
func bar<T>(_ x: [Int], _ y: T) { print("A") }
func bar<T: P>(_ x: [Any], _ y: T) { print("B") }
bar([1], Y()) // A
bar
is more specific, but requires a variance conversion from [Int]
to [Any]
.
For why you can convert from (Y?) -> Void
to (P) -> Void
, see this. Note that Y
is a subtype of Y?
, by compiler magic.
Since it is so consistent, this behaviour seems to be by design. Since you can't really make Y
not a subtype of Y?
, you don't have a lot of choices if you want to get the desired behaviour.
I have this work around, and I admit it's really ugly - make your own Optional
type. Let's call it Maybe<T>
:
enum Maybe<T> {
case some(T)
case none
// implement all the Optional methods if you want
}
Now, your (Maybe<Y>) -> Void
won't be converted to (P) -> Void
. Normally I wouldn't recommend this, but since you said:
in the real-world code where I encountered this, the closure has multiple params, any of them can be optional, so this would lead to a combinatorial explosion.
I thought reinventing Optional
might be worth it.
Related Topics
Multidimensional Dictionaries Possible in Swift
Alamofire 3 Custom Encoding to Alamofire 4 Custom Encoding
Swift Objc_Getassociatedobject Always Nil
How to Check Whether an Object Is Kind of a Dynamic Class Type in Swift
Swift: Hashable Struct with Dictionary Property
Workarounds for Generic Variable in Swift
Swift String Permutations Allowing the Same Strings
How to Keep a Reference to Another Object in the Parameters of the Class
Cloudkit Ckqueryoperation Doesn't Get All Records
Loop Over Multiple Uialertcontroller'S
Nstableview Inside Nspopover Looks Different as Standalone
Dynamic Uicollectionview Inside Dynamic Uitableviewcell
Swift Convert Decimal Coordinate into Degrees, Minutes, Seconds, Direction
Firebase Auth Internal Error on Login Attempt
How to Use Enumeratedate in Swift 3 to Find All Sundays the Last 50 Years