How to set a weak reference to a closure/function in Swift? - ios

In HMSegmentedControl, I'd like to set the segmentedControl.indexChangeBlock to an instance method to handle the action.
The official example is: https://github.com/HeshamMegid/HMSegmentedControl/blob/master/HMSegmentedControlExample/HMSegmentedControlExample/ViewController.m (Line 63 ~ 68), but that's Objective-C.
In Swift, functions are first class citizens. So I wanna set an instance method to this block property.
But my code would lead to a circular reference, it seems that I should define a weak reference:
class ExampleVC: UIViewController {
var segmentedControlIndex: Int = 0
override func viewDidLoad() {
let segmentedControl3 = HMSegmentedControl(sectionImages: ... , sectionSelectedImages: ... )
segmentedControl3.frame = ...
segmentedControl3.indexChangeBlock = someInstanceMethod
}
func someInstanceMethod(index: Int) {
segmentedControlIndex = index
}
}
However, I cannot define a weak reference to a non-class type. What can I do? Is it legal to do this?

[unowned self] is dangerous. What this does is to tell the runtime 'Assume self has not been released, don't worry about checking.' If self does get released in the meantime, your application will SEGFAULT.
In this case, { [weak self] in self?.someInstanceMethod($0) } will break the reference cycle, and turns into a no-op if self is released.
[weak self] is always safe, while [unowned self] can introduce app crashes if you modify other areas of your code (like view hierarchy, for example)...

Instead of defining weak reference to the closure, you should use "Capture List" in the closure.
segmentedControl3.indexChangeBlock = { [unowned self] in self.someInstanceMethod($0) }
As far as I know, this is the only way to avoid strong reference cycles.

Related

UIView.animate() : do I need a weak reference to self in the animation block? [duplicate]

This question already has answers here:
Is it necessary to use [unowned self] in closures of UIView.animateWithDuration(...)?
(7 answers)
Closed 2 years ago.
After some research I found out my app was using way too much energy because of several UIView animations throughout the app, where I was capturing the related UIViewController in the completion block, without making a weak reference to it.
So actually, I changed this:
func animate() {
UIView.animate(withDuration: 0.3, animations: {
self.label.alpha = 0.5
}) { _ in
self.animate()
}
}
Into this :
func animate() {
UIView.animate(withDuration: 0.3, animations: {
self.label.alpha = 0.5
}) { [weak self] _ in
self?.animate()
}
}
However, I would like to know if I need to do the same with the animation block (the self.label.alpha = 0.5 one) ?
Thank you for your help
No, it is not needed in this case. animations and completion are not retained by self so there is no risk of strong retain cycle.
duplicated of Is it necessary to use [unowned self] in closures of UIView.animateWithDuration(...)?
You don't need to use [weak self] in UIView.animate(). You need to use weak when retain cycle is possible and animations block is not retained by self.
There is an article on medium about where [weak self] may and may not be needed
For more information:
Automatic Reference Counting
Closures
There might be another issue for the energy problem.
What do you mean by:
my app was using way too much energy
I don't see any immediate relation between keeping a weak reference on your view controller and saving energy.
Capturing self without increasing its retain count in your closure (that's what we mean by having a weak reference on an object) means that if no other strong reference on your view controller exists, then your view controller will be released sooner. Maybe you will save some RAM in a very short term.
I would suggest to investigate somewhere else to find where your "energy" issue comes from.
There are a lot of articles about the use of weak keyword.
https://medium.com/flawless-app-stories/you-dont-always-need-weak-self-a778bec505ef
Sure, you do need to use the "weak self" concept there.
In fact note: it is indeed very common in that situation that a VC is trashed during an animation ... so indeed, it's one of the places you "most need" to use the weak-self idea. It's a very common mistake in projects to forget that in an animation.
By the way, here's a handy syntax any time you need weak self:
func animate() {
UIView.animate(withDuration: 0.3, animations: { [weak self] in
guard let self = self else { return print("gotchya!") }
self.label.alpha = 0.5
}) { [weak self] in
guard let self = self else { return print("gotchya!") }
self.animate()
}
}
Adding this line ..
guard let self = self else { return }
.. can seem a bit long-winded, but, it means you then don't need the "?"
after "self" every time you use it in long blocks.
Often you will have many uses of "self ..." inside such a block, and it seems more consistent to just use the "let self = self" idiom.
So even if there is only one line of code in the block (as in your two examples) it's a good way to be absolutely consistent everywhere and keep things simple.
Note that whenever you have a { return } you can just add a print statement so that you know what is going on during development ..
.... { [weak self] in
guard let self = self else { return print("I avoided a crash, woot!") }
or
.... { [weak self] in
guard let self = self else { return print("logical disaster near line 66") }
You do not have to do that, "{ return }" is fine. It's just for your convenience.
What the hell is this "self = self" business?
If you find the "self = self" idiom confusing ....... honestly, just don't worry about it. Always use that idiom. It's really just the "standard" thing you will see everywhere.
Always go for simple consistency in your code base!
More weak self mysteries ...
Here's a interesting QA from a handsome list member: Where does the weak self go?
And later there's this sort of confusion to worry about: What is the difference between a weak reference and an unowned reference?

Should I weakify "local" variables used in a block?

This is not another question about [weak self]. This is about use of variables not contained by self, but rather by the wrapping function.
func someFunction(){
someOtherFunction(completionBlock:{ [weak self] in
self?.doStuff()
})
}
As far as I understand, I need the [weak self] in order to prevent a retain cycle.
But what if I need to use a variable from the wrapping function, like this:
func someFunction(){
let someVariable = MyObject()
someOtherFunction(completionBlock:{ [weak self] in
self?.doStuff(with: someVariable)
})
}
This works, which makes me wonder.. How, and how long is someVariable held in memory? Can it create its own tiny retain cycle where my completion block strongly references the local someVariable? How will they be released? Should I add [weak self, weak someVariable] in the block? But then, won't someVariable be released immediately after I call someOtherFunction, because it's the end of this function - and the end of someVariable's lifetime..?
I'm having trouble completely understanding references, and can't see how my completionBlock and someVariable will ever be released.. Are blocks even released?
Any variable referenced inside a closure will be strongly retained by that closure. You can adjust that by including a closure capture list (e.g. [weak self]), which allows you to specify the particular memory management pattern of references captured in the closure.
func someFunction(){
let someVariable = MyObject()
someOtherFunction(completionBlock:{ [weak self] in
self?.doStuff(with: someVariable)
})
}
Here, someVariable is retained by the closure, as you have stated. In this case, it has to be, because nobody else cares about it. As you've mentioned in comments, if you used a capture list of [weak someVariable] then it would always be nil when the completion block executed, as it has gone out of scope in it's original function.
A "tiny retain cycle" isn't being created. A retain cycle has to be a cycle - that is, A holds a strong reference to B, which holds a strong reference to A. someVariable doesn't have references to anything.
Once someOtherFunction has finished with the reference to the completion closure, everything goes away. The closure is just another variable as far as someOtherFunction is concerned, and it will survive as long as it is in scope.
Should I weakify “local” variables used in a block? - no, as they will then be nil by the time the block comes to use them.
I would like to mention not so clear option, what is very usual place to create retain cycle and where you should be aware of weaken variables.
Lets consider this situation:
func someFunction() {
let object = Something()
object.handler = { [weak self] in
self?.doStuff(with: object)
}
}
Now there is retain cycle, and object cannot be deallocated until somebody manually unset the handler. Because now object strongify itself in the captured block.
So better solution is:
func someFunction() {
let object = Something()
object.handler = { [weak self, unowned object] in
self?.doStuff(with: object)
}
}
And good practice is pass the object as argument in handler
func someFunction() {
let object = Something()
object.handler = { [weak self] (object) in
self?.doStuff(with: object)
}
}
So signature of this should look like:
class Something {
var handler:((Something) -> Void)?
deinit {
print("retain cycle is not here")
}
}

Optimizing capture lists

Is there such a thing? Is there any difference between the two below? Is one more "correct" than the other?
All objects are properties of self (let's say a view controller) and have the same lifetime as self. We can introduce an object with a shorter lifetime than self, which would be weak, but the same question applies.
objectOne.doSomething { [unowned self] in
self.objectTwo.finish()
self.tableView.reloadData()
// self.someDelegate?.didFinishSomething()
}
vs
objectOne.doSomething {
[unowned objectTwo = self.objectTwo,
unowned tableView = self.tableView
// weak someDelegate = self.delegate
] in
objectTwo.finish()
tableView.reloadData()
// someDelegate?.didFinishSomething()
}
Apple has this example in their docs:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
In this case, delegate can have a shorter lifetime than self, but why not use it like this?
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
Yes, there is an important difference. In the case of the Apple docs, the code alternative you presented:
lazy var someClosure: () -> String = {
[unowned self] in
// closure body goes here
self.delegate?.doSomething()
}
will look up the current delegate on self when the closure runs.
In the Apple example version:
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
delegate?.doSomething()
}
the weak delegate var in the capture list is copying the delegate pointer on self that exists at the time of closure declaration, not execution. So if the value of self.delegate changes after the closure is declared and is different at the time the closure runs, the Apple version of the closure will have a nil delegate (assumedly since the reference to the old delegate was weak) and do nothing.
So as a general rule, copying values or references in capture lists ([someIdentifier = someProperty]) is how to use the values or references as they exist at the moment the closure is defined. Whereas declaring weak or unowned self in the capture list ([weak self]) and then accessing properties on that weak reference ({ self?.someProperty }) will get the values of the properties as they exist when the closure is executed.
One of the problems that [unowned objectOne = self.objectOne] might cause is with lazy var UIViews and racing conditions: if you aren't careful and the lazy init gets called from different threads, two instances might end up being created. Furthermore, if your superview.addSubview(objectOne) call is in the lazy init, both instances will be added to the superview, and objectOne will point to one of the two instances.

ARC in Swift how to resolve strong reference cycle when assign property as function

Flowing code, I did try to create an object assign object property to a functions. And after init object I did try assign it to nil. But object did not release (because deinit never called).
I think problem is strong reference cycle between property and owner object. If really has strong reference cycle here, how to resolve this problem when assign property directly with a function?
class MyClass {
var aProperty: (() -> ())?
init() {
// problem when assign property as a method
self.aProperty = aMethod
}
func aMethod() {
print("method!!!")
}
deinit {
print("MyClass is being deinitialized")
}
}
var instance: MyClass? = MyClass()
instance?.aProperty?()
instance = nil
You resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure’s definition. A capture list defines the rules to use when capturing one or more reference types within the closure’s body. As with strong reference cycles between two class instances, you declare each captured reference to be a weak or unowned reference rather than a strong reference. The appropriate choice of weak or unowned depends on the relationships between the different parts of your code.
lazy var someClosure: Void -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}
from
Strong Reference Cycles for Closures
In your case you should apply capture list when assigning a method to the property like this
init() {
self.aProperty = { [unowned self] in self.aMethod() }
}
You can still use a capture list to prevent the cycle. Just wrap the method call in a closure as shown in the code below.
class MyClass {
var aProperty: (() -> ())?
init() {
// use a capture list to prevent a reference cycle
self.aProperty = { [unowned self] in self.aMethod() }
}
func aMethod() {
print("method!!!")
}
deinit {
print("MyClass is being deinitialized")
}
}
var instance: MyClass? = MyClass()
instance?.aProperty?()
instance = nil
This eliminates the strong reference cycle in my testing.

Correct placement of capture list in nested closures in swift

Where do I define captured references for nested closures in Swift?
Take this code as an example:
import Foundation
class ExampleDataSource {
var content: Any?
func loadContent() {
ContentLoader.loadContentFromSource() { [weak self] loadedContent in
// completion handler called on background thread
dispatch_async(dispatch_get_main_queue()) { [weak self] in
self?.content = loadedContent
}
}
}
}
class ContentLoader {
class func loadContentFromSource(completion: (loadedContent: Any?) -> Void) {
/*
Load content from web asynchronously,
and call completion handler on background thread.
*/
}
}
In this example, [weak self] is used in both trailing closures, however the compiler is perfectly happy if I omit [weak self] from either one of the trailing closures.
So that leaves me 3 options for defining my capture list:
define captures on every nested closure leading up to the reference
define captures on the first closure only.
define captures on only the most nested closure that actually uses the reference.
My question is:
If I know that my ExampleDataSource could be nil at some point, what is the best option to go with?
It is important to note that GCD dispatch_async will NOT cause a retain cycle. In other words, when the block has finished executing, GCD will not retain any references made within the block.
The same is not true for strong references between classes, or strong references within a closure assigned to a property of an instance. Apple Documentation
That being said, in this example, the correct answer is option 2, to define captures on the first closure only.
For testing purposes I modified the code slightly:
class ExampleDataSource {
init() {
print("init()")
}
deinit {
print("deinit")
}
var content: Any?
func loadContent() {
print("loadContent()")
ContentLoader.loadContentFromSource() { [weak self] loadedContent in
dispatch_async(dispatch_get_main_queue()) {
print("loadedContent")
self?.content = loadedContent
}
}
}
}
class ContentLoader {
class func loadContentFromSource(completion: (loadedContent: Any?) -> Void) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
sleep(5) // thread will hang for 5 seconds
completion(loadedContent: "some data")
}
}
}
First I create, var myDataSource: ExampleDataSource? = ExampleDataSource().
Then I run myDataSource.loadContent().
Before the completion handler gets a chance to run, I set myDataSource = nil, removing all references to it.
The debug console indicates that a reference to self was not retained:
init()
loadContent()
deinit
loadedContent
Looks like we found our answer! But just for completion's sake, let's test the alternatives...
If [weak self] is instead captured on only the inner most trailing closure, GCD will retain ExampleDataSource until the block has finished executing, which explains why the debug would instead look like this:
init()
loadContent()
loadedContent
deinit
The same thing will happen if no capture list is included and we never optionally unwrapped self, although the compiler, does try to warn you!
While it isn't technically incorrect to include [weak self] captures in all trailing closures, it does detract from the readability of code and doesn't feel very 'Swift-like'.

Resources