Are there problems with strong retain issues with code such as this: - ios

In the following code, is there a problem with the self in self.tableView.reloadData() being a strong reference, and should it be changed to be weak, or is it ok as it is?
class SomeViewController : UIViewController {
fileprivate var notificationToken: NotificationToken? = nil
...
override func viewDidLoad()
{
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(onNotification), name: NSNotification.Name(SomeNotification), object: nil)
realmNotificationToken = blockedList.observe({ (changes: RealmCollectionChange) in
switch changes
{
case .initial:
self.tableView.reloadData() // Case 1
break
...
#objc func onNotification()
{
DispatchQueue.main.async{
self.tableView.reloadData() // Case 2
}
}
In both of these examples are there any problems with retain cycles due to the fact self is a strong reference, and it should change to weak?
In both instances, what is the life time of the two blocks within which self.tableView.reloadData() is being used? If the lifetime is ephemeral then there's no problems with using strong, are these blocks however long lived?

Case 2 is a non escaping closure so there is no issue.
Case 1 is #escaping so you need to use a weak or unowned reference. #escaping means you are passing the closure to something that may outlive the object that created the closure (ie you ViewController). If you strongly capture self in the #escaping then your ViewController now lives for as long as the closure lives, and the closure lives until you cancel your subscription. If you only cancel the subscription when the ViewController deintializes then you now have a cycle. The closure can never be released because the subscription never dies and the ViewController can never die because the subscription never dies.
EDIT:
I should add you actually don't need self in either case; you can simply capture the tableview (if its implicitly unwrapped it will be desugared into a plain optional, which is fine):
realmNotificationToken = blockedList.observe({ [tableView] (changes: RealmCollectionChange) in
switch changes {
case .initial:
tableView?.reloadData()

Related

iOS Memory management. Closures

I have a question about memory management in iOS.
As I know we have ARC that looks at a number of strong references to the object and once it's become 0 object will be deallocated.
Here is a code sample that makes me confused
final class SecondVC: UIViewController {
let titleLabel: UILabel = UILabel()
let network = Network()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .red
self.view.addSubview(titleLabel)
network.makeCall {
self.titleLabel.text = "Title"
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.navigationController?.popViewController(animated: true)
}
deinit {
print("SecondVC deinit called")
}
}
final class Network {
func makeCall(completion: #escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
}
}
deinit {
print("Network deinit called")
}
}
As I understand VC holding network with a strong reference.
At the same time network capture VC with a strong reference.
The completion callback was never called. So the number of references shouldn't go to 0.
But deinit called for both objects.
The questin is
Is there a memory leak? And why deinit is called if in theory we have object that should not be deallocated.
UPD
So, the answer is.
No one captures completion. Completion is released after makeCall and self captured by it is also released.
As you are using #escaping in your closure there is nothing hanging on to the reference so the count can be reset
here's a good article on #escaping
https://www.donnywals.com/what-is-escaping-in-swift/
** Edit,
Sorry this was poorly worded - "in your closure there is nothing hanging on to the reference" was the key bit from this as the closure is never called - the escaping part was confusing things as its really unrelated to the OP's question, sorry for the confusion

Why is this a retain cycle?

I have basic understanding of ARC but in the following example I suddenly get really confused.
FeedViewController has a strong reference of NetworkHelper, then the NetworkHelper has a function which takes a closure and call it later.
So here's the confusion:
the closure is passed from FeedViewController to NetworkHelper, And this block is not being retained inside NetworkHelper, so why does NetworkHelper has a strong reference of NetworkHelper? this is stated in an article but I just could't figure out why. It makes sense to me only if NetworkHelper keep a strong reference to the block.
class NetworkHelper {
func getFeed(completion: #escaping ([FeedItem]) -> Void) {
Alamofire.request(…).responseJSON { (response) in
if let value = response.result.value {
if let json = JSON(value)[Constants.items].array {
completion(json.flatMap(FeedItem.init))
}
}
}
}
}
class FeedViewController {
var tableView: UITableViewController
var feedItems: [FeedItem]
var networkHelper: NetworkHelper
override func viewDidLoad() {
...
networkHelper.getFeed() { items in
self.feedItems = items
self.tableView.reloadData()
}
}
}
Technically, there is no cycle.
First of all, NetworkHelper never owns anything, it just passes a closure to Alamofire.
Alamofire holds to that closure, which retains a FeedViewController instance (as self). However, Alamofire is not owned by FeedViewController, therefore there is no cycle.
It's true that while the request is running, FeedViewController cannot be deallocated because the completion callback prevents that, but that could be an expected behavior and there is definitely no ownership cycle.

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")
}
}

How to quit "DispatchQueue.main.asyncAfter" in Swift

I want to quit "DispatchQueue.main.asyncAfter" when deinit is called.
subView.swift
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
self.doSomething()
}
func doSomething(){
if self.subView.flgA == false { //error because subView's deinit is already called
//...
}
}
When ViewController do _ = self.navigationController?.popViewController(animated: true) and deinit is called, deinit in ViewController and subView is called at first and after a few minutes doSomething() is called.
I want to stop doSomething() when popViewController is executed.
How can I do it?
You could schedule a Timer with this code block
let timer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { [weak self] timer in
self?.doSomething()
}
hold on to the timer and cancel it before popViewController like this:
timer.invalidate()
Notice the [weak self] and the self?.domeSomething() which I put there to avoid the hard reference to the viewcontroller and read Laffen's more detailed answer on this.
In Swift we have something called ARC(Automatic Reference Counting).
ARC will make sure any object with at least one strong reference to it, will not be removed from memory.
In your case you're creating a strong reference to self in the closure of the async task created by DispatchQueue.main.asyncAfter.
You need to tell the compiler that this reference is either weak or unowned(See attached link for more info.), this will enable the instance of self to be deinitialised even though you have a reference to self from the closure.
The weak keyword can be used in cases where you want the closure to run and make actions that doesn't require a reference to self. This is helpful to use if you don't know if self is alive or not.
The unowned keyword can be used in cases where you don't need the closure to run without a reference to self. This must be used in cases where you know self self is still alive.
Getting a weak or unowned reference of self in the closure can be achieved like in the example below:
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
[weak self] in
self?.doSomething()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
[unowned self] in
self.doSomething()
}
It's worth mentioning that if you're not using a deadline, but calling .async { ... } directly does not result in capturing self and therefore can be used safely without defining weak/unowned self.

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

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.

Resources