I've done some research on closures, closures that receive parameters, trailing closures, and completion handlers, but I'm having difficulty understanding when the two arguments to completion, manager and file are passed. In the pick() function definition, there is nowhere in the function scope that calls the completion with completion(manager, file) syntax. There is, however, a present method and I think I am missing something about present() that may include the call for the completion closure with proper arguments. I would appreciate your help.
public func pick(from vc: UIViewController?, withCompletion completion: #escaping (_ manager: HSDriveManager?, _ file: GTLRDrive_File?) -> Void) {
viewer?.completion = completion
viewer?.shouldSignInOnAppear = true
//As of now, present() seems to include the calling of the completion closure.
//self is the HSDriverPicker class
print(type(of: self))
vc?.present(self, animated: true)
}
The code below is the function call for pick. What confuses me is that in order for manager and file to act like arguments of the completion closure somewhere in the function call there has be a part that passes those arguments. I don't see them. I would appreciate your insight on what exactly the present method does and whether it takes care of calling the closure with necessary arguments.
picker.pick(from: self) {
(manager, file) in
print("picked file: \(file?.name ?? "-none-")")
let destinationPath = "/Users/james/Desktop/tests"
manager!.downloadFile(file!, toPath: destinationPath, withCompletionHandler: {
error in
if error != nil {
print("Error downloading : \(error?.localizedDescription ?? "")")
}
else {
print("Success downloading to : \(destinationPath)")
}
})
}
The function present(_:animated:) won't be responsible for calling the completion closure. viewer?.completion = completion means viewer will take care of calling the completion closure in its scope(that's why #escaping is used, i.e the closure will outlive the scope that you've passed it to). The two arguments manager and file aren't supposed to be passed by the client but are exposed to the client so that whoever calls the picker.pick could use these properties and perform the certain action that will then called inside viewer. The closure with parameters simply means the client could use that parameter without worrying about who and when will those parameters be passed.
Related
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 an error when I try to assign a value to the function parameter while inside a completion block, I get an error that reads 'escaping closures can only capture inout parameters explicitly by value' .
How could I fix this? Any tip is much appreciated!
func fetchCurrentUser(user: inout User? ) {
self.fetchUser(withId: AuthProvider.sharedInstance.currentUserId(), completionHandler: {
fetchedUser in
guard let newUser = fetchedUser else { return }
user = newUser // error Here
})
}
This will not work, because you use a completion handler. The self.fetchUser will (almost) immediately return and the completion handler will be executed whenever the background work (most likely a network request) is finished.
Your function fetchCurrentUser calls self.fetchUser and than returns so it will return before the completion block is even executed.
You cannot use inout parameter on escaping closures (this is what the error message also tells you). A escaping closure is a closure which will be executed after the function which you pass it in returns.
You can either rewrite your function to also use a completion hander or change you function to wait for the completion handler to run before ending the fetchCurrentUser function. But for the second approach please be aware that this also will block the caller of the function from executing anything else.
I suggest this refactor:
func fetchCurrentUser(callback: #escaping (User) -> ()) {
self.fetchUser(withId: AuthProvider.sharedInstance.currentUserId(), completionHandler: {
fetchedUser in
guard let newUser = fetchedUser else { return }
callback(newUser)
})
}
or if you want fetchCurrentUser to be synchronous you could use semaphores
I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.
I have a function with this prototype:
func myFunction(completionHandler:((response:[NSString:AnyObject])->Void)?))
The completionHandler prototype can be passed as closure or as a function... passing it as closure I know how to define a capture list with this syntax [weak self], but how can I define a capture list if instead of defining the closure directly in the function argument I want to pass a function name?
myFunction(anotherFunction) // how to set capture list from here?
VS
myFunction{
[weak self] (response) in
}
```
EDIT-----
A possible solution is to wrap the function code into a block, set the capture list and execute the block... but it sounds so strange :/
myFunction(anotherFunction) // how to set capture list from here?
.
.
.
func anotherFunction(response:[NSString:AnyObject]) {
let safeBlock = {
[weak self] in {
self?.callSomethingSafely()
}
}
safeBlock()
}
EDIT (based on correction from Hamish below):
I'm not aware of a way to force a referenced method to internally use a weak version of a captured variable. As you have in your example, it's up to to the actual method implementation to do that or not.
However, it's worth noting that unless you are going to be storing a reference to that completion handler indefinitely, you don't need to worry about weak self.
I assume that completion handler will be called as soon as some asynchronous task that myFunction kicks off is completed. In that case, any references captured by the completion handler will only be held until the completion handler runs. Then those references will be released and there won't be any retain cycles. Weak self in closures in only important if "self" retains the closure and the closure captures "self", setting up a circular reference / retain cycle.
#MatterGoal your solution will still produce a reference cycle.
I am assuming you are aware of the situations where we should use a capture list. For a scenario like myFunction(anotherFunction), we cannot define a capture list for a method (func) named anotherFunction itself. At least for now, lets hope in future we can.
We can only define a capture for a closure. A method can act as a closure with same signature but it (method) does not support capture list for itself.
Solutions:
Make a lazy var anotherFunction = { } in which we can define capture list.
Make your function return a closure:
func anotherFunction() -> (() -> Void) {
return { [weak self] in
// do anything you want with self? properties or methods.
// this won't create a strong reference cycle
}
}