Does function from argument get captured in closure? - ios

I am trying to clear my code form memory leaks and I am not sure in some situations. I am adding capture lists to all my closures to make them stop capturing and making retain cycles, but not sure about functions passed to closure form arguments... onInternetFailed gets to closure and gets strongly captured.
Situation like this:
public func send<Data>(_ operation: CSOperation<Data>, _ title: String, _ isProgress: Bool,
_ canCancel: Bool, _ isFailedDialog: Bool, _ onInternetFailed: (() -> Void)?,
_ onSuccess: ((Data) -> Void)?) -> CSOperation<Data> {
let process = operation.send(listenOnFailed: false).process!
if isProgress {
let cancelAction = canCancel ? CSDialogAction(title: .cs_dialog_cancel) { [unowned operation] in
operation.cancel()
} : nil
let progress = show(progress: title, cancel: cancelAction)
process.onDone { [unowned progress] _ in progress.hideDialog() }
}
//TODO : does function get captured strongly in closure ?
process.onFailed { [unowned self, unowned operation] failed in
onProcessFailed(operation, failed, title, isProgress, isFailedDialog, onInternetFailed, onSuccess)
}
onSuccess.notNil { [unowned process] in process.onSuccess($0) }
return operation
}

Closures (functions) have reference semantics and will always be captured strongly. In fact, you cannot change the capture mode to weak or unowned. If you think about it, it wouldn't make sense either.
When you deal with completion handlers, the best practice you can follow is to ensure that the completion handlers will be called eventually. This ensures, the closure is released (actually the objects it references).
It's a common programmer error to forget to call a completion handler, or to call it twice. A completion handler must be called once (eventually) and only once. For example, check CSOperation if it actually calls either onFailed or onSuccess when the task completes, when it bails out early, or in any other possible case.
Update
When analysing your code, the object operation returns an object process (presumably holding a strong reference itself).
This process value has a closure value onFailed which will be assigned a closure which imports unowned self, unowned operation and two other closures onInternetFailed and onSuccess.
(I omit the other details).
When you now look at it, it's the value operation that is responsible to hold everything together.
Note also, that there is nowhere a "completion handler" pattern *). Instead, your handlers are kept in instance variables. If these get called, they remain allocated.
So, even if your operation completes, and calls onFailed eventually - nothing gets deallocated.
It's your responsibility to set the "completion handlers" to nil after they have been called. Alternatively, set process to nil, alternatively set operation to `nil.
IMHO, the design should be made more simple and more easy to comprehend.
What I do generally, is to avoid storing "completion" handlers in instance variables. This opens a host of potential errors (due to reference cycles) which you cannot avoid in the code itself, but must be avoided by the caller by enforcing a convention and following strict rules which you have to document, which in turn leads to "leaking implementation details", ...
But you can alleviate the problems by ensuring your "completion handler" will be set to nil once it has been called.
Even, better avoid storing completion handlers in instance variables and apply the "completion handler pattern".
Completion handler pattern
The handler will not be stored in an object as an instance variable:
func doWorkAsync(completion: #escaping (Result) -> Void) {
self.workerQueue.async {
// work
completion(result)
}
}
"Operation Style" variant which clears the completion handler after completion:
class MyOperation {
var completion: ((Result) -> Void)?
init(completion: (Result) -> Void) {
self.completion = completion
}
func start() {
assert(self.completion != nil)
doWorkAsync { result in
let completion = self.completion
self.completion = nil
completion?(result)
}
}
}
Note that - in certain perspective - a Closure is nothing else than an Operation, and an operation can be represented as a Closure. In other words, it's possible to refactor code using Operations and replace it with pure Closures, thus avoiding any issues stemming from using Operations.

Related

async/await, Task and [weak self]

Okay so we all know that in traditional concurrency in Swift, if you are performing (for example) a network request inside a class, and in the completion of that request you reference a function that belongs to that class, you must pass [weak self] in, like this:
func performRequest() {
apiClient.performRequest { [weak self] result in
self?.handleResult(result)
}
}
This is to stop us strongly capturing self in the closure and causing unnecessary retention/inadvertently referencing other entities that have dropped out of memory already.
How about in async/await? I'm seeing conflicting things online so I'm just going to post two examples to the community and see what you think about both:
class AsyncClass {
func function1() async {
let result = await performNetworkRequestAsync()
self.printSomething()
}
func function2() {
Task { [weak self] in
let result = await performNetworkRequestAsync()
self?.printSomething()
}
}
func function3() {
apiClient.performRequest { [weak self] result in
self?.printSomething()
}
}
func printSomething() {
print("Something")
}
}
function3 is straightforward - old fashioned concurrency means using [weak self].
function2 I think is right, because we're still capturing things in a closure so we should use [weak self].
function1 is this just handled by Swift, or should I be doing something special here?
Bottom line, there is often little point in using [weak self] capture lists with Task objects. Use cancelation patterns instead.
A few detailed considerations:
Weak capture lists are not required.
You said:
in traditional concurrency in Swift, if you are performing (for example) a network request inside a class, and in the completion of that request you reference a function that belongs to that class, you must pass [weak self] …
This is not true. Yes, it may be prudent or advisable to use the [weak self] capture list, but it is not required. The only time you “must” use a weak reference to self is when there is a persistent strong reference cycle.
For well-written asynchronous patterns (where the called routine releases the closure as soon as it is done with it), there is no persistent strong reference cycle risk. The [weak self] is not required.
Nonetheless, weak capture lists are useful.
Using [weak self] in these traditional escaping closure patterns still has utility. Specifically, in the absence of the weak reference to self, the closure will keep a strong reference to self until the asynchronous process finishes.
A common example is when you initiate a network request to show some information in a scene. If you dismiss the scene while some asynchronous network request is in progress, there is no point in keeping the view controller in memory, waiting for a network request that merely updates the associated views that are long gone.
Needless to say, the weak reference to self is really only part of the solution. If there’s no point in retaining self to wait for the result of the asynchronous call, there is often no point in having the asynchronous call continue, either. E.g., we might marry a weak reference to self with a deinit that cancels the pending asynchronous process.
Weak capture lists are less useful in Swift concurrency.
Consider this permutation of your function2:
func function2() {
Task { [weak self] in
let result = await apiClient.performNetworkRequestAsync()
self?.printSomething()
}
}
This looks like it should not keep a strong reference to self while performNetworkRequestAsync is in progress. But the reference to a property, apiClient, will introduce a strong reference, without any warning or error message. E.g., below, I let AsyncClass fall out of scope at the red signpost, but despite the [weak self] capture list, it was not released until the asynchronous process finished:
The [weak self] capture list accomplishes very little in this case. Remember that in Swift concurrency there is a lot going on behind the scenes (e.g., code after the “suspension point” is a “continuation”, etc.). It is not the same as a simple GCD dispatch. See Swift concurrency: Behind the scenes.
If, however, you make all property references weak, too, then it will work as expected:
func function2() {
Task { [weak self] in
let result = await self?.apiClient.performNetworkRequestAsync()
self?.printSomething()
}
}
Hopefully, future compiler versions will warn us of this hidden strong reference to self.
Make tasks cancelable.
Rather than worrying about whether you should use weak reference to self, one could consider simply supporting cancelation:
var task: Task<Void, Never>?
func function2() {
task = Task {
let result = await apiClient.performNetworkRequestAsync()
printSomething()
task = nil
}
}
And then,
#IBAction func didTapDismiss(_ sender: Any) {
task?.cancel()
dismiss(animated: true)
}
Now, obviously, that assumes that your task supports cancelation. Most of the Apple async API does. (But if you have written your own withUnsafeContinuation-style implementation, then you will want to periodically check Task.isCancelled or wrap your call in a withTaskCancellationHandler or other similar mechanism to add cancelation support. But this is beyond the scope of this question.)
if you are performing (for example) a network request inside a class, and in the completion of that request you reference a function that belongs to that class, you must pass [weak self] in, like this
This isn't quite true. When you create a closure in Swift, the variables that the closure references, or "closes over", are retained by default, to ensure that those objects are valid to use when the closure is called. This includes self, when self is referenced inside of the closure.
The typical retain cycle that you want to avoid requires two things:
The closure retains self, and
self retains the closure back
The retain cycle happens if self holds on to the closure strongly, and the closure holds on to self strongly — by default ARC rules with no further intervention, neither object can be released (because something has retained it), so the memory will never be freed.
There are two ways to break this cycle:
Explicitly break a link between the closure and self when you're done calling the closure, e.g. if self.action is a closure which references self, assign nil to self.action once it's called, e.g.
self.action = { /* Strongly retaining `self`! */
self.doSomething()
// Explicitly break up the cycle.
self.action = nil
}
This isn't usually applicable because it makes self.action one-shot, and you also have a retain cycle until you call self.action(). Alternatively,
Have either object not retain the other. Typically, this is done by deciding which object is the owner of the other in a parent-child relationship, and typically, self ends up retaining the closure strongly, while the closure references self weakly via weak self, to avoid retaining it
These rules are true regardless of what self is, and what the closure does: whether network calls, animation callbacks, etc.
With your original code, you only actually have a retain cycle if apiClient is a member of self, and holds on to the closure for the duration of the network request:
func performRequest() {
apiClient.performRequest { [weak self] result in
self?.handleResult(result)
}
}
If the closure is actually dispatched elsewhere (e.g., apiClient does not retain the closure directly), then you don't actually need [weak self], because there was never a cycle to begin with!
The rules are exactly the same with Swift concurrency and Task:
The closure you pass into a Task to initialize it with retains the objects it references by default (unless you use [weak ...])
Task holds on to the closure for the duration of the task (i.e., while it's executing)
You will have a retain cycle if self holds on to the Task for the duration of the execution
In the case of function2(), the Task is spun up and dispatched asynchronously, but self does not hold on to the resulting Task object, which means that there's no need for [weak self]. If instead, function2() stored the created Task, then you would have a potential retain cycle which you'd need to break up:
class AsyncClass {
var runningTask: Task?
func function4() {
// We retain `runningTask` by default.
runningTask = Task {
// Oops, the closure retains `self`!
self.printSomething()
}
}
}
If you need to hold on to the task (e.g. so you can cancel it), you'll want to avoid having the task retain self back (Task { [weak self] ... }).

Should I use `weak self` when making asynchronous network request?

Here is my method to fetch some data from the network:
func fetchProducts(parameters: [String: Any],
success: #escaping ([Product]) -> Void)
As you noticed, it has escaping closure. Here is how I call above method in ViewModel:
service.fetchProducts(parameters: params, success: { response in
self.isLoading?(false)
/// doing something with response
})
The question is should I capture self weakly or strongly? Why? I think I can capture it strongly. Because, fetchProducts is a function which has closure as a parameter. But, I might be wrong. But, from other perspective, I think it should be weak. Because, ViewModel has strong reference to service, service has strong reference to success closure which has strong reference to self (which is ViewModel). It creates retain cycle. But deinit of ViewModel is called anyway, after ViewController which owns ViewModel is deinitialized. It means that there was no retain cycle. Why?
As long as your viewmodel is a class, you have to capture self weakly, otherwise you'll have a strong reference cycle. Since fetchProducts is asynchronous, its success closure might be executed after your viewmodel has already been deallocated - or would have been deallocated if the closure wasn't holding a strong reference to it. The strong reference in the async closure will block the viewmodel from being deallocated.
If you call service.fetchProducts in a class AND access self inside the async closure, you do need [weak self]. If you were to do this in a value type (struct or enum) OR if you didn't access self inside the closure, you don't need [weak self] - in a value type, you cannot even do [weak self].
service.fetchProducts(parameters: params, success: { [weak self] response in
self?.isLoading?(false)
/// doing something with response
})

#escaping closure actually runs before return

I am implementing download request from a remote source and i ran into the notion of #escaping function. As Apple says:
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.
But I actually noticed (with the breakpoint tool) that it calls and implements before return statement.
static func fetchFeaturedApps(completionHandler: #escaping ([AppCategory]) -> ()) {
let urlString = "https://api.letsbuildthatapp.com/appstore/featured"
URLSession.shared.dataTask(with: URL(string: urlString)!) {
(data, response,error) -> Void in
if error != nil {
print(error?.localizedDescription)
return
}
do {
let json = try(JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) as! Dictionary<String, Any>
var appCategories = [AppCategory]()
// invokes before return [![enter image description here][1]][1]
completionHandler(appCategories)
for dict in json["categories"] as! [[String: Any]] {
let appCategory = AppCategory()
appCategory.setValuesForKeys(dict)
appCategories.append(appCategory)
}
print(appCategories)
DispatchQueue.main.async {
// completionHandler(appCategories)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}.resume()
}
Then and of course after it deals with "completionHandler" it goes on implementing function further, as if i send it plain closure. It turns out #escaping closure call before return statement, strictly in the place where I call it in function body.
But I think maybe I am wrong? Maybe Apple keeps in mind another scenario? Please how do I need to understand #escaping notation with Apples quote about calling them after return? Actually in the example it calls before return , why?
You said:
It turns out #escaping closure [is called] strictly in the place where I call it in function body.
Yep, that's exactly what happens. It's called wherever you place it in your code. If you happen to call it before you return from the method, that's what it's going to do.
As others have pointed out, the fact that it is declared as #escaping means that it can be called later, not that it will necessarily be called later.
In fact, this pattern of calling an #escaping closure synchronously (i.e. before the method returns) is not uncommon. For example, you'll see this if you're dealing with network requests where responses can be cached. In that scenario, you might check your cache and call the closure immediately if the resource has already been retrieved, but call the closure asynchronously if it wasn't previously cached and you have to now retrieve the resource asynchronously from the web. E.g., you might have something like:
func fetchImage(for identifier: String, completion: #escaping (UIImage?) -> Void) {
if let image = cache.retrieveImage(for: identifier) {
completion(image)
return
}
webService.fetchImageAsynchronously(for: identifier) { image in
completion(image)
}
}
Note, just because the closure is designated as #escaping, that doesn't mean that my code path is required to call it asynchronously, regardless. I can call the closure either synchronously or asynchronously, whatever makes sense.
That having been said, if you have a method where you know that you will always call the closure synchronously, you would not use the #escaping designation. Not only would gratuitous use of #escaping in non-escaping scenarios make one's code unclear, but the #escaping designation prevents the compiler from performing certain types of optimizations. So we only use #escaping where it's needed, i.e. in those cases that we know it will or can be called asynchronously.
As it is said in documentation:
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.
Declaring a closure #escaping does not make it execute after your function returns. It just means that it may or may not execute after function returns, which completely depends on your code.
Concerning your code, your closure is directly called in the function context, so it is no wonder that closure is executed before the function returns. If you would like to make it execute after the function returns, you may want to use some multithreading mechanism, like GCD or OperationQueue.

Closure cannot implicitly capture a mutating self parameter

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.

Concern about memory when choosing between notification vs callback closure for network calls?

Many posts seem to advise against notifications when trying to synchronize functions, but there are also other posts which caution against closure callbacks because of the potential to inadvertently retain objects and cause memory issues.
Assume inside a custom view controller is a function, foo, that uses the Bar class to get data from the server.
class CustomViewController : UIViewController {
function foo() {
// Do other stuff
// Use Bar to get data from server
Bar.getServerData()
}
}
Option 1: Define getServerData to accept a callback. Define the callback as a closure inside CustomViewController.
Option 2: Use NSNotifications instead of a callback. Inside of getServerData, post a NSNotification when the server returns data, and ensure CustomViewController is registered for the notification.
Option 1 seems desirable for all the reasons people caution against NSNotification (e.g., compiler checks, traceability), but doesn't using a callback create a potential issue where CustomViewController is unnecessarily retained and therefore potentially creating memory issues?
If so, is the right way to mitigate the risk by using a callback, but not using a closure? In other words, define a function inside CustomViewController with a signature matching the getServerData callback, and pass the pointer to this function to getServerData?
I'm always going with Option 1 you just need to remember of using [weak self] or whatever you need to 'weakify' in order to avoid memory problems.
Real world example:
filterRepository.getFiltersForType(filterType) { [weak self] (categories) in
guard let strongSelf = self, categories = categories else { return }
strongSelf.dataSource = categories
strongSelf.filteredDataSource = strongSelf.dataSource
strongSelf.tableView?.reloadData()
}
So in this example you can see that I pass reference to self to the completion closure, but as weak reference. Then I'm checking if the object still exists - if it wasn't released already, using guard statement and unwrapping weak value.
Definition of network call with completion closure:
class func getFiltersForType(type: FilterType, callback: ([FilterCategory]?) -> ()) {
connection.getFiltersCategories(type.id).response { (json, error) in
if let data = json {
callback(data.arrayValue.map { FilterCategory(attributes: $0) } )
} else {
callback(nil)
}
}
}
I'm standing for closures in that case. To avoid unnecessary retains you just need to ensure closure has proper capture list defined.

Resources