How to weak reference a function passed as a parameter - ios

I have a strongly referenced model in my view controller that has a function listenToQueue which "listens" to my Firebase database for real time updates. Whenever an update occurs, it passes back an object to my view controller, which then calls a function. Here is my code:
eventModel.listenToQueue { [weak self] queuer in
self?.queuerDidChange(queuer: queuer)
}
This works. However, originally my code looked like this:
eventModel.listenToQueue(updateHandler: queuerDidChange)
This caused a retain cycle between the model and the view controller. However, that code looks cleaner, so I'm wondering if there's a way to pass the queuerDidChange function via a weak reference to self? I tried this already, but the retain cycle is still there:
weak var weakSelf = self
eventModel.listenToQueue(updateHandler: weakSelf?.queuerDidChange)
Is it possible to do what I want, or shall I just stick to the code I've got?

weak var weakSelf = self
eventModel.listenToQueue(updateHandler: weakSelf?.queuerDidChange)
Above code is the same code as:
eventModel.listenToQueue(updateHandler: queuerDidChange)
Because you declare weakSelf and use it immediately. weakSelf?.queuerDidChange has no relation to weakSelf, instead it already contains reference to self itself. I assume queuerDidChange member function. So the only way to avoid retain cycle is what you call the dirty way.
eventModel.listenToQueue { [weak self] queuer in
self?.queuerDidChange(queuer: queuer)
}

I noticed this in one of my apps. I like the look of passing in the method itself, but I also had to use the weak reference technique you mentioned.
This makes sense, I think, because method implementations are held on the class itself, and self is bound to that implementation when classes are instantiated. Therefore a method will always have a strong reference to self.
And in Swift, function parameters are strongly referenced. I don’t think there’s a way to pass any parameter using a weak reference.

Related

Create a Weak UnsafeMutableRawPointer

So I'm trying to use the CoreAudio method AUGraphAddRenderNotify(...) but I need a reference to the class that created this notification within the notification block. Because this is a C function, I can't simply add a [weak self] in closure capture. Looking at the Documentation, the last parameter of this method is allowed to be an UnsafeMutableRawPointer that will be passed in during the execution of the block as the first parameter. Following this suggestion, here is the code that I have:
let selfPointer = Unmanaged.passUnretained(self).toOpaque()
AUGraphAddRenderNotify(graph, { (audioPlayerPointer, _, _, _, _, _) -> OSStatus in
let audioPlayer = Unmanaged<AudioPlayer>.fromOpaque(audioPlayerPointer).takeUnretainedValue()
...
return noErr
}, selfPointer)
Here is my question:
I need to figure out how I can safely get the value behind this pointer (accounting for nil). More specifically, I want to safely access the audioPlayer and make sure that it hasn't been deallocated by the time I use it. Currently, everything works just fine until the audioPlayer gets deallocated and then my app crashes. I know that I can use AUGraphRemoveRenderNotify(...) to stop the notification before the object gets deallocated but unfortunately this method is not what I'm looking for. How can I check if the object that the pointer is pointing to has already been deallocated?
Thanks in advance!
Weak references don't really work like that
Interestingly, weak references don't actually point to the target object that they model. They point to side tables, whose lifetime is different from the target object.
A side-table entry is allocated when the first weak reference to an object is made.
The creation of every weak reference increments the ref count of the side-table entry, and every destruction of a weak reference decrements it.
Once the target object is deallocated, the side-table entry remains in place. That way, all the weak references don't become dangling pointers.
After eventual deallocation of the target object, all attempts to access a weak ref to the (now-dead) cause the weak-ref to be nil-ed out (which is what you observe as a user), but also deincrements the side-table entry
Thus, every weak reference either needs to be destroyed (e.g. goes out of scope) or attempted to be accessed before the side table entry expires.
Since these side table entries aren't exposed to "user land" Swift code, you can't make a raw pointer to them, and so you can't really deal with weak references in this way.
Alternate ideas
I have a few ideas of what you can do instead, though I haven't tried them.
You can exploit UnsafeMutableRawPointer pointer to pass in a Weak<T> wrapper, like:
struct Weak<T: AnyObject> {
wear var object: T?
}
Though I think it'll have to be a class, in this case.
or for some other mechanism, such as passing in a closure (which weakly captures the object)

Avoiding [weak self] for simple operations?

For short-running operations, is it acceptable to avoid [weak self]? For example, URLSession will retain the closure from dataTask(with:completion:):
final class ViewController: UIViewController {
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data else { return }
let decodedString = String(bytes: data, encoding: .utf8)
DispatchQueue.main.async {
self.label.text = decodedString
}
}.resume()
}
}
In this case, the closure captures self strongly, which means even if this ViewController is held in memory by the closure. URLSession will hold the closure until the data task is complete, which means the life cycle of the ViewController can potentially be extended until dataTask completes.
In this situation, should we use capture lists to avoid this behavior? Is my reasoning correct that there's no reference cycle here?
the life cycle of the ViewController can potentially be extended until dataTask completes
So the question is whether that would be coherent. It might even be a good thing. If it would, then fine, and there’s no need for weak self, as there is no retain cycle because the
url session is shared.
But when the url session is an instance
property and has a real delegate, things are much more complicated and
you really can get a retain cycle, because the session retains its delegate which might be retaining the session.
If you are worried about reference cycles, you usually don't get one when using URL requests. The thing is that the URL request finishes sooner or later (after several minutes) and you controller gets released. The reference cycle is only temporary and it won't cause a memory leak.
The question is whether you want to keep the controller in memory even if the user has already closed the controller and it won't be ever shown again. It won't probably cause any problems but it's still wasteful. You are holding to memory you don't need and that cannot be reused.
Also note that you might actually want to cancel the running request when the controller is dismissed to avoid sending/receiving data that is not necessary anymore.
In my opinion, you shouldn't worry that much about reference cycles and think more about ownership. A strong reference means that something is owned. The request has no reason to "own" the controller. It's the other way around - the controller owns and manages the request. If there is no ownership, I would use weak just for clarity.
Is my reasoning correct that there's no reference cycle here?
There is no reference cycle here. ViewController is not retaining the dataTask completion handler. You can think of this as iOS keeping a strong reference to both the view controller and the completion handler, and the completion handler also keeping a strong reference to the view controller. There is no strong reference from the view controller back to the completion handler, or to any chain of objects with a reference to the completion handler, so you are cycle-free. Look for this same pattern in UIView.animate, where you are again sending closures to iOS instead of storing them locally.
For short-running operations, is it acceptable to avoid [weak self]?
The duration of the work is not a factor. The two pertinent questions are:
Does a cycle of references exist?
Will the cycle of references be broken?
Take this example:
class BadVC: UIViewController {
private lazy var cycleMaker: () -> Void = { print(self) }
override func loadView() {
view = UIView()
cycleMaker()
}
}
BadVC here manages to create a reference cycle that will never be broken as soon as it loads its view. The fact that cycleMaker() will execute in nanoseconds does not save us from a memory leak.
Pragmatically, there is a third question:
Does this code avoid permanent reference cycles in a way that is difficult to understand, easy to break, or unreliable, so reference cycles are likely to emerge in the future due to misuse or modification?
You can break reference cycles manually. For example:
class StillBadVC: UIViewController {
private lazy var cycleMaker: () -> Void = { print(self) }
override func loadView() {
view = UIView()
cycleMaker()
}
func breakCycle() {
cycleMaker = { }
}
}
Here, we are in danger because StillBadVC has a strong reference to cycleMaker and cycleMaker captures a strong reference to StillBadVC. The cycle will be broken as long as someone remembers to call breakCycle(), at which point the view controller will remove its strong reference to cycleMaker, allowing cycleMaker to deallocate. However, the cycle will not be broken if someone forgets to call breakCycle(). Calling a method called breakCycle() is not usually a part of the contract for using a view controller, so we would expect StillBadVC to result in memory leaks in practice.
You definitely should use [weak self] here, not because of any risk of strong reference cycle, but simply because this closure exists solely to update a label. There is no point in writing code that deliberately keeps the view controller and its views in memory so you can update a label in a view that may have been dismissed and is no longer visible.
The weak keyword does not exist solely to avoid strong reference cycles, but rather to accurately represent the object ownership and manage object lifespans. You shouldn’t misrepresent the object ownership graph just for the sake of saving the few keystrokes associated with [weak self] capture list.
I think you've already got your answer here. It's not a reference cycle.
But to build a systematic approach, my advice here is one more simpler. Forget thinking about leaks and stuff.
Think about ownership and flow control and then memory-management
Ownership: Does this object need to own this other object? Should an object own its delegate? Should a subview own its parentiew? Does this request own this viewController?
Flow Control: How soon do I want to de-allocate this object? Immediately or upon the view being removed from the screen?
Memory-management: Is this a strong reference cycle?
This thought process not only helps you distinguish a true memory leak from something that isn't a leak. It also helps you design and read your code better and not just slavishly dump [weak self] all over the place.

Swift Memory management when pass a closure as parameter to singleton

I'm aware of the fact that closure can create retain cycles if it is assigned to a property of a class and instance properties of the class are used inside of the closure. But
1) what about the closure is not assigned to the class property but passed as parameter to a singleton's class method ?
2) How the memory is managed in this case ?
In a method of my controller (UIViewController) I have something like:
MySingleton.classMethod(parameters ..., completion: { () -> Void in
/**
doing stuff here
*/
})
If You are not assigning the closure to a property, but just passing it to a function You need to consider if the closure will be escaping or noescape. In Swift 3 by default all closures passed to functions are non-escaping.
Here is a little bit more info on the matter:
"noescape" - the passed closure is invoked before the return of the function
"escaping" - If a closure is passed as an argument to a function and it is invoked after the function returns, the closure is escaping.
Simple explanation : We need to mark closure as escaping when we pass it to a function and the closure will be called after this function returns.
General rule is when the closure is escaping You need to use capture list to prevent retain cycles.
Example
let closure = { [weak someVariable] (name: Type) -> Void in
....
// code
}
Additional info:
One weird thing is that optional closures are treated as escaping. And when we explicitly add escaping keyword, there is a compile error -escaping attribute only applies to function types.
See the below links for more info.
https://bugs.swift.org/browse/SR-2053
https://stackoverflow.com/a/39619298/5388473
https://stackoverflow.com/a/39846519/5388473
Update
The idea of using weak or unowned in the capture lists of escaping closures is that essentially We don't know what will happen with the passed escaping closure, it may be called sometime later from another function or it may be stored in some object, which may lead to a strong retain cycle.
weak vs unowned vs strong capture
For more detailed information check Apple ARC docs.
From Apple docs:
Swift provides two ways to resolve strong reference cycles when you
work with properties of class type: weak references and unowned
references.
Weak and unowned references enable one instance in a reference cycle
to refer to the other instance without keeping a strong hold on it.
The instances can then refer to each other without creating a strong
reference cycle.
Use a weak reference when the other instance has a shorter
lifetime—that is, when the other instance can be deallocated first.
Use an unowned reference when the other instance has the same lifetime
or a longer lifetime.
Keep in mind that the weak approach will add a boiler plate to the code and will be a little bit more slow, because ARC will add code for setting the weak variables to nil on their deallocation. It is a good practice to follow the rules stated above, when choosing weak or unowned.

Block/Closure Understanding

Need clarification on blocks and closure.
How blocks will retain the object? or why we need to use only weak inside block? What will happen if we don't follow this? Or please give some clarity on block.
The below one os for closure.
I have written some code like this. favouriteButton is a property of self.
favouriteButton.hidden = false
dispatch_async(dispatch_get_main_queue(), {
self._collectionView.reloadData()
})
It didn't gave any error. So I thought of doing UI in main thread. So I moved the code to disable hidden inside block like below.
dispatch_async(dispatch_get_main_queue(), {
favouriteButton.hidden = false
self._collectionView.reloadData()
})
It shows an error like
reference to property 'favouriteButton' in closure requires explicit
'self'
dispatch_async(dispatch_get_main_queue(), {
self.favouriteButton.hidden = false
self._collectionView.reloadData()
})
Could any one please explain how to use closure/block effectively.
Does the blocks and closures work in the same way?
In Swift (and Objective-C), a block is a closure. The term closure refers to an individually-executable block of code that captures the values of variables in the enclosing scope. In the case of Swift, the enclosing scope is usually a function, and only variables used within the block are captured.
The reason you need to preface class-level references (properties and function calls) with self. is to make explicit the capturing of self. Doing so allows you to specify how self (or any other object reference) is captured: strong (default) or weak.
There are two reasons to be careful with retaining objects (keeping strong references) within a block.
The most common concern is creating a retain cycle. This is where the block retains a strong reference to an object, which in turn has a strong reference to the block. Until one of the references is explicitly broken, neither the block, nor the object, will be released. (Releasing a block simply cleans up the captured variables. The executable code remains.)
A strong reference to an object within a block can keep the object alive longer than intended. For example, if a block keeps a reference to a view controller that is popped off a navigation stack, you likely don't want that block to act on the view controller when its executed. This can be avoided by capturing a weak reference to the view controller. This allows the view controller to be deallocated when it's popped, and the block becomes a no-op.

iOS. what does "self" mean in a dispatched block?

I have see many blocks use "self.xxx" in a block, then how can I make sure the "self" is the instance I want?
Example:
I am in instance A, whose delegate is B.
And then I call [A.delegate dispatchBlockTest]
The dispatchBlockTest in instance B is like this:
dispatch_async(dispatch_get_main_queue(DISPATCH_UEUE_PRIORITY_DEFAULT, 0),^{
[self printClassName];
});
});
Then, the "self" in the block is definitely B? not A?
Any sort of help is appreciated, thanks.
Fonix's comment is right on. For more information, you can check out this page from the official Apple docs. Specifically take a look at the "Blocks Can Capture Values from the Enclosing Scope" section. The meaning of a variable in a block is always "captured" when the block is declared, so local variables, properties, and references to self are all based on the scope of where the block is declared (in your case, the scope in class A) and NOT based on where the block is called (in your case, class B).
On a side note, one subtle thing it's worth knowing about using self with blocks is that you can create a type of memory leak known as a strong reference cycle or a retain cycle (Check out the section on weak properties here for an explanation). In general, it's good practice to always use a weak reference to self in blocks (Apple has a good example here). Most of the time, using self in a block won't create a strong reference cycle, but if you always use a weak reference to self in a block, you don't have to think about whether or not you risk a reference cycle.

Resources