Wednesday, September 20, 2017

Swift 3 - weak and unowned references

To avoid, retain cycle we go with a weak reference in iOS.
In swift 3 we can go for weak or unowned to declare it as a weak reference.

In this post let’s see when to use weak and when to use unowned incase of 
closures and incase of normal property declarations.

weak always gives an optional, Where as unowned means we are sure like It is not going to be nil at any point of time.
If you are declaring something as unowned, Make sure It always will have a value.

Incase of Closures :-


------------------------------------------------------------------------------------------------------

DispatchQueue.main.async() { [unowned self] () in
      self.hideLoader()
}

------------------------------------------------------------------------------------------------------


In this block, I have used unowned reference for self, because I am sure like 
self can be never be nil when this block gets executed.

------------------------------------------------------------------------------------------------------

DispatchQueue.main.async { [weak self] in
    guard let strongSelf = self else { return }
    strongSelf.hideLoader()
}

------------------------------------------------------------------------------------------------------

In the above closure, I have taken self as weak and using that in my block. 
This means, self can be nil at any point of time.
So, Inside the block before using self, I am checking that with a guard statement.

From this, weak is an optional type whereas unowned is not.

Incase of Properties :-


Consider the following retain cycle. Person and Car created a retain cycle here.
The dealloc of both the classes will not get called here.

------------------------------------------------------------------------------------------------------

class Car {
    var driver:Person?
    deinit {
        print("Car dealloc")
    }
}

class Person {
    var car: Car?
    deinit {
        print("Person dealloc")
    }
}

var driver: Person? = Person()
var car: Car? = Car()

driver?.car = car!
car?.driver = driver!

car = nil
driver = nil

------------------------------------------------------------------------------------------------------

Car can exist without a driver and driver can exist without a car here.
To break this cyclic relationship, person can have a weak reference to his/her car as it is meaningful in this case.
(Person may not have a car, But Car should have a driver)

------------------------------------------------------------------------------------------------------

class Person {
    weak var car: Car?
    deinit {
        print("Person dealloc")
    }
}

------------------------------------------------------------------------------------------------------

Now the dealloc methods of Car and Person will get called as we have broke the retain cycle by giving a weak reference to car property of Person class.

This is the use case of weak reference.

Let’s see an use case of unowned reference.

Car can exist without a key, where as car keys existence is meaningless If that is not associated with a car.

------------------------------------------------------------------------------------------------------

class Car {
    var key:CarKey?
    deinit {
        print("Car dealloc")
    }
}

class CarKey {
    let car: Car
    init(car: Car) {
        self.car = car
    }
    deinit {
        print("CarKey dealloc")
    }
}

var car: Car? = Car()
var key: CarKey? = CarKey(car: car!)

car?.key = key

car  = nil
key = nil

------------------------------------------------------------------------------------------------------

We need to initialise a CarKey with a car instance always. So CarKey car instance can not be nil and it 
will always contain a value as we are initialising CarKey with always a car instance.

This also creates a retain cycle. In this case we can break this retain cycle with unowned as shown below.

------------------------------------------------------------------------------------------------------

class CarKey {
    unowned let car: Car
    init(car: Car) {
        self.car = car
    }
    deinit {
        print("CarKey dealloc")
    }
}

------------------------------------------------------------------------------------------------------

Conclusion As Per Apple Docs:-

Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization.


Hope this post is useful. Feel free to comment incase of any queries.


No comments:

Post a Comment