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
}
}
Related
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.
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 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.
Is there any way to indicate to a "client" of a specific method that a closure parameter is going to be retained?
For instance, having the following code:
import Foundation
typealias MyClosureType = () -> Void
final class MyClass {
private var myClosure: MyClosureType?
func whatever(closure: MyClosureType?) {
myClosure = closure
}
}
Anyone could start using this class and passing closures to the method whatever without any idea about if it is actually being retained or not. Which is error prone and could lead to memory leaks.
For instance, a "client" doing something like this, would be never deallocated
final class MyDummyClient {
let myInstance = MyClass()
func setUp() {
myInstance.whatever {
self.whateverHandler()
}
}
func whateverHandler() {
print("Hey Jude, don't make it bad")
}
}
That is why I would like to know if there is any way to prevent this type of errors. Some type of paramater that I could add to the definition of my method whatever which gives a hint to the client about the need to weakify to avoid leaks
Whether the closure parameter is escaping or non-escaping is some indication to the caller whether it might be retained. In particular, a non-escaping closure param cannot be retained by a function call.
Per SE-0103, non-escaping closures (currently marked #noescape) will become the default in Swift 3, and you'll have to write #escaping if you want to save the closure, so situations like this will become a little more obvious.
Otherwise, there is no language feature to help you here. You'll have to solve this problem with API design and documentation. If it's something like a handler, I'd recommend a property, obj.handler = { ... }, or a method like obj.setHandler({ ... }) or obj.addHandler({ ... }). That way, when reading the code, you can easily tell that the closure is being saved because of the = or set or add.
(In fact, when compiling Obj-C, Clang explicitly looks for methods named set...: or add...: when determining whether to warn the user about retain cycles. It's possible a similar diagnostic could be added to the Swift compiler in the future.)
With the specific case you're presenting the closure itself is the only thing that will be retained, so if you correctly add [weak self] to your closure when you call it there shouldn't be any issues.
I'm not sure what issue you're trying to protect against, but you might also thing about using delegation (protocols) rather than a closure.
class HTMLElement {
let name : String
let text: String?
//Declaring a lazy variable that has a strong reference to this closure
lazy var asHTML: Void -> String = {
//Optional binding here
if let text = self.text {
return "<\(self.name)>\(text)<\(self.name)>"
} else {
return "<\(self.name) >"
}
}
init(name: String, text: String? = nil){
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
My Question is: Why is the closure declared Lazy, I know it has something to do with self not being known in the closure, but isn't that the same case for the init method where self hasn't been created?
Secondly,Where exactly is the strong reference cycle in this code example, is it self that strongly references to asHTML, if so where is the second part of the strong referencing that causes the cycle?
Third, Why is the constant text property an optional when constants cannot change value(from nil to a value and back to nil)?
Lastly, What does it mean to have the parameter text: String? = nil in the init method when the init method is used to accept parameters sent by the user?
Sorry for this long question, I'm just confused on the closure strong reference cycle....although I do understand strong reference cycles between class properties and class instances.
1
lazy is used for attributes that are only created when called upon. So before you call myClass.myLazyAttribute it will not take up any space. This also means that it will init after the class has initialised, which can be very useful.
In this case lazy is used to get access to self, like you stated, because self is not available until the instance has been initialised.
2
The apple doc from where code is.
Closures capture the values used in them. In this case it captures self.
It does not create a Strong Reference Cycle between class A and class B, but between itself and a closure. It makes a lot more sense if you imagine that the operation inside the closure takes a very long time. During the execution something else has happened and you want to deinit the instance. But the closure has captured self and it will keep the instance alive until it is done.
By using [unowned self] in you can again deinit the instance while the closure is running. Although this will crash your app.
good info on this specific use : link
In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self] or [weak self].
What a Strong Reference Cycle in essence is:
you have an instance of a class
the instance has a reference count higher than 0
there is no longer a reference to the instance available to your program.
Or even shorter: the reference count of the instance is higher than the number of accessible references.
In this case the reference count of self goes up by 1 because it is captured by the closure. We can not access that reference because we can not say something like: closure.selfAttribute, so we can not set that to nil. Only when the closure is finished will the reference count go down by 1 again.
3
It is an optional constant, but it's initial value is set in the init method of the class. So it can receive a value in the init method, but it will be immutable. This is called a late init.
4
This is a function parameter with a default value.
func someFunction(myParamWithDefaultValue : Int = 10) {
print(myParamWithDefaultValue)
}
someFunction() // 10
someFunction(5) // 5