I have read a lot of material on stack overflow and I just cannot figure this one out:
I have been this line of code from an online source for hours and I just don't know why the closure that is being passed into a function is escaping, here is the code:
func composeFunction(functionA: #escaping (Int) -> String, functionB: #escaping (String) -> String) -> ((Int) -> String) {
return {
number in
functionB(functionA(number))
}
}
From apple's documentation, closures are escaping when:
1) Asynchronous operation that runs on a background thread
2) The closure is interactive with properties outside of it's scope (using self)
But I don't see those are happening, many help will be appreciated!
Thanks!
your func composeFunction returns a ((Int) -> (String)) and that is exactly a closure. Of course now this means functionA and functionB are going to be escaping because we don't know when and where this closure will be called. Moreover, this is because it needs to know if it should keep the reference to the objects passed in / being manipulated. For example, if all your closure parameters had (() -> Void) instead and you also returned (() -> Void) then it would not need to be escaping.
{
number in
functionB(functionA(number))
}
is a closure. Returning it causes both functionB and functionA to escape, because it becomes unknown at what point this closure will be called or deallocated.
This is different from just return functionB(functionA(number)), which causes the immediate invocation of both of those functions, and causes them to never escape the composeFunction context.
Related
This down code works just fine! As soon as I update testFunc, with '#escaping', it start make error about
Escaping closure captures mutating 'self' parameter
struct TestType {
var string: String {
didSet(oldValue) {
if (oldValue != string) {
testFunc(string: string, result: { resultValue in
value = resultValue
})
}
}
}
private(set) var value: String
}
func testFunc(string: String, result: (String) -> Void) {
result(string + " updated!")
}
my goal is to be able use:
func testFunc(string: String, result: #escaping (String) -> Void) {
result(string + " updated!")
}
How can I solve the issue without using a reference type?
The problem with capturing mutating self in an #escaping closure in a struct is there are really only two choices in how Swift might theoretically attempt to do it.
The first is to capture a reference to the struct, but in many cases it lives on the stack. Since the #escaping closure could be called later, that means writing to the position on the stack where self was, but likely isn't there anymore. If that happens when the stack has shrunk, then you're writing to an address that is effectively unreachable by any other code. If it happens when the stack has grown back (or larger), then you're likely stomping on unrelated data, possibly some function's return address. If you're lucky the result will be that the program crashes. If you're unlucky, it will silently do the wrong thing.
Another possible implementation is that Swift could capture a copy, which of course, could be safely written to, but would be inaccessible to any other code. That's pretty pointless.
There is a third option Swift could do, which is it could box the struct (that is actually place it on the heap). The problem is that nothing else would know about the heap location. Again that's pretty pointless... and much much slower than allocating things on the stack.
If you really need to capture a mutating self, then you need TestType to be a class, but that means the rest of your code has to be written with reference semantics in mind.
Very likely, you need to think about whatever problem you're trying to solve in a different way. Without knowing what that is, concrete solutions are impossible to suggest.
I had a function
func login<Bool> (parameters: [(String, Any)],
completion: #escaping (Bool) -> Void) {
//Do something
}
And whenever I called the completion handler like so
completion(false)
or
completion(true)
XCode kept telling me: "Cannot convert value of type 'Swift.Bool' to expected argument type 'Bool'"
Eventually, I removed the at the beginning of the function, and the error went away. I thought that was declaring the type for the function, but I'm frankly not sure what that means, or what <> does despite googling. I'm sure it's explained well, but I'm not grasping the concept from googling alone. And why is Swift.Bool not able to be converted to Bool. I was able to find that there is an objective C version of bool and I thought maybe it was asking for that, but that didn't work either. What does that mean a Bool is?
The syntax func login<Bool> defines a type parameter called Bool. It has nothing to do with Swift.Bool. It's just a name you've defined. It's the same as if you declared a local variable var Bool: String. You'd have a variable named Bool that is actually a String. Don't do that.
If you want the value to always be Bool, remove the type parameter. This isn't generic.
func login(parameters: [(String, Any)],
completion: #escaping (Bool) -> Void) {
For details on the <...> syntax and generics see Generics in The Swift Programming Language.
I have a predefined function that has a completion param:
func checkNotificationEnabled(_ resultBlock : ((Bool)->())? = nil){
Bool enabled = false
... a big block of code that gets enabled value
...
... end block
resultBlock?(enabled)
}
I need to get the true/false and pass it to another function:
#objc
func isNotificationEnabled(_
resolve: RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock
) -> Void {
checkNotificationEnabled { (enabled:Bool) in
resolve(enabled)
}
}
Got the error: Escaping closure captures non-escaping parameter 'resolve'
How can I pass enabled to resolve ?
Presuming RCTPromiseResolveBlock on func isNotificationEnabled to be some block that you're trying to execute with respect to completion of func checkNotificationEnabled, the completion actually 'escapes' (outlives) the scope of the function, and the compiler simply complains that your RCTPromiseResolveBlock may not be alive (in execution) during the completion callback
You'll have to mark #escaping to the 'resolve' parameter to get around this.
You'll definitely get more clarity when you understand what escaping closures are. Have a look at this question: Escaping Closures in Swift
Hope this helps.
resolve argument is passed to a function checkNotificationEnabled but is not marked #escaping
(Bool)->())? = nil optional is nil by default, so no need to assign nil
(Bool)->() this is equal to more readable version Void.
typealias ResultBlock = (Bool) -> Void
func checkNotificationEnabled(_ resultBlock: ResultBlock?) {
var enabled = false
... a big block of code that gets enabled value
...
... end block
resultBlock?(enabled)
}
#objc
func isNotificationEnabled(_
resolve: #escaping RCTPromiseResolveBlock, rejecter reject: RCTPromiseRejectBlock) {
checkNotificationEnabled { enabled in
resolve(enabled)
}
}
Escaping closures
A closure is said to escape a function when the closure is passed as
an argument to the function, but is called after the function returns.
When you declare a function that takes a closure as one of its
parameters, you can write #escaping before the parameter’s type to
indicate that the closure is allowed to escape.
One way that a closure can escape is by being stored in a variable
that is defined outside the function. As an example, many functions
that start an asynchronous operation take a closure argument as a
completion handler. The function returns after it starts the
operation, but the closure isn’t called until the operation is
completed—the closure needs to escape, to be called later.
source
I am trying to understand 'Closure' of Swift more precisely.
But #escaping and Completion Handler are too difficult to understand
I searched many Swift postings and official documents, but I felt it was still not enough.
This is the code example of official documents
var completionHandlers: [()->Void] = []
func someFunctionWithEscapingClosure(completionHandler: #escaping ()->Void){
completionHandlers.append(completionHandler)
}
func someFunctionWithNoneescapingClosure(closure: ()->Void){
closure()
}
class SomeClass{
var x:Int = 10
func doSomething(){
someFunctionWithEscapingClosure {
self.x = 100
//not excute yet
}
someFunctionWithNoneescapingClosure {
x = 200
}
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
completionHandlers.first?()
print(instance.x)
I heard that there are two ways and reasons using #escaping
First is for storing a closure, second is for Async operating purposes.
The following are my questions:
First, if doSomething executes then someFunctionWithEscapingClosure will executing with closure parameter and that closure will be saved in global variable array.
I think that closure is {self.x = 100}
How self in {self.x = 100} that saved in global variable completionHandlers can connect to instance that object of SomeClass ?
Second, I understanding someFunctionWithEscapingClosure like this.
To store local variable closure completionHandler to global variable 'completionHandlerswe using#escaping` keyword!
without #escaping keyword someFunctionWithEscapingClosure returns, local variable completionHandler will remove from memory
#escaping is keep that closure in the memory
Is this right?
Lastly, I just wonder about the existence of this grammar.
Maybe this is a very rudimentary question.
If we want some function to execute after some specific function. Why don't we just call some function after a specific function call?
What are the differences between using the above pattern and using an escaping callback function?
Swift Completion Handler Escaping & Non-Escaping:
Assume the user is updating an app while using it. You definitely want
to notify the user when it is done. You possibly want to pop up a box
that says, “Congratulations, now, you may fully enjoy!”
So, how do you run a block of code only after the download has been
completed? Further, how do you animate certain objects only after a
view controller has been moved to the next? Well, we are going to find
out how to design one like a boss.
Based on my expansive vocabulary list, completion handlers stand for
Do stuff when things have been done
Bob’s post provides clarity about completion handlers (from a developer point of view it exactly defines what we need to understand).
#escaping closures:
When one passes a closure in function arguments, using it after the function’s body gets executed and returns the compiler back. When the function ends, the scope of the passed closure exist and have existence in memory, till the closure gets executed.
There are several ways to escaping the closure in containing function:
Storage: When you need to store the closure in the global variable, property or any other storage that exist in the memory past of the calling function get executed and return the compiler back.
Asynchronous execution: When you are executing the closure asynchronously on despatch queue, the queue will hold the closure in memory for you, can be used in future. In this case you have no idea when the closure will get executed.
When you try to use the closure in these scenarios the Swift compiler will show the error:
For more clarity about this topic you can check out this post on Medium.
Adding one more points , which every ios developer needs to understand :
Escaping Closure : An escaping closure is a closure that’s called after the function it was passed to returns. In other words,
it outlives the function it was passed to.
Non-escaping closure : A closure that’s called within the function it was passed into, i.e. before it returns.
Here's a small class of examples I use to remind myself how #escaping works.
class EscapingExamples: NSObject {
var closure: (() -> Void)?
func storageExample(with completion: (() -> Void)) {
//This will produce a compile-time error because `closure` is outside the scope of this
//function - it's a class-instance level variable - and so it could be called by any other method at
//any time, even after this function has completed. We need to tell `completion` that it may remain in memory, i.e. `escape` the scope of this
//function.
closure = completion
//Run some function that may call `closure` at some point, but not necessary for the error to show up.
//runOperation()
}
func asyncExample(with completion: (() -> Void)) {
//This will produce a compile-time error because the completion closure may be called at any time
//due to the async nature of the call which precedes/encloses it. We need to tell `completion` that it should
//stay in memory, i.e.`escape` the scope of this function.
DispatchQueue.global().async {
completion()
}
}
func asyncExample2(with completion: (() -> Void)) {
//The same as the above method - the compiler sees the `#escaping` nature of the
//closure required by `runAsyncTask()` and tells us we need to allow our own completion
//closure to be #escaping too. `runAsyncTask`'s completion block will be retained in memory until
//it is executed, so our completion closure must explicitly do the same.
runAsyncTask {
completion()
}
}
func runAsyncTask(completion: #escaping (() -> Void)) {
DispatchQueue.global().async {
completion()
}
}
}
/*the long story short is that #escaping means that don't terminate the function life time until the #escaping closure has finished execution in the opposite of nonEscaping closure the function can be terminated before the closure finishes execution Ex:
*/
func fillData(completion: #escaping: () -> Void){
/// toDo
completion()
}
//___________________________
//The call for this function can be in either way's #escaping or nonEscaping :
fillData{
/// toDo
}
/* again the deference between the two is that the function can be terminated before finish of execution nonEscaping closure in the other hand the #escaping closure guarantees that the function execution will not be terminated before the end of #escaping closure execution. Hope that helps ***#(NOTE THAT THE CLOSURE CAN BE OF ANY SWIFT DATA TYPE EVEN IT CAN BE TYPEALIAS)*/
I have the following functions:
func moveThing(thing: AnyObject, toLeft length: Int) {}
func moveThing(thing: AnyObject, toRight length: Int) {}
However, when I pass one of the functions as a parameter, compiler complains about "Ambiguous use of 'moveThing'"
func exec(function: (AnyObject, Int) -> ()) {}
exec(moveThing) // Apparently ambiguous
exec(moveThing as (AnyObject, toLeft: Int) -> ()) // Still ambiguous
How can I solve the ambiguity?
Swift Evolution proposal SE-0021 addressed this by allowing moveThing(_:toLeft:) to disambiguate these functions, and it is implemented in Swift 2.2.
I know this is an old thread, but I ran into this related situation recently. Might help somebody.
TLDR
Ultimately I solved the problem by just wrapping the method call in a closure like this:
let cancel: (Text) -> Alert.Button = { .cancel($0) }
Long Winded Explanation
When I type Alert.Button.cancel (from the SwiftUI framework), auto-complete shows me these options:
cancel(action: (() -> Void)?) // 1
cancel(label: Text) // 2
cancel() // 3
cancel(label: Text, action: (() -> Void)?) // 4
Naturally I thought this bit of code should work:
let cancel: (Text) -> Alert.Button = Alert.Button.cancel(_:)
However, the compiler says Cannot convert value of type '((() -> Void)?) -> Alert.Button' to specified type '(Text) -> Alert.Button'. Apparently it translates that signature to mean method 1 instead of method 2.
As it turns out, method 2 does not actually exist. Looking at the actual declarations in Alert.swift we find:
public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
public static func cancel(_ action: (() -> Void)? = {}) -> Alert.Button
So, cancel(label:) is rendered by auto-complete from cancel(_:action:) because the parameter action has a default value.
Conclusion: I made the mistake of assuming auto-complete was showing me individual method declarations. If the compiler tells you a method signature doesn't match what you expect, check the method declaration.
An interesting question! I don't think you can at the moment, as it seems that parameter names are not part of the function reference name, though I couldn't find anything from Apple's reference documentation that explicitly dictates this.
Of course, for this particular example, you can use
exec({ moveThing($0, toLeft: $1) } )
exec({ moveThing($0, toRight: $1) } )
but I see what you are after with the simplified example.