Tuesday, December 5, 2017

Difference between weak self and unowned self #iOS #swift

If you remember the Automatic Reference Counting(ARC) concept, you must heard about retain cycle or Strong reference cycle.

I will explain about what is retain cycle. Let's go through the below example

class Person {
    var name:String
    var address:String
    var apartment:Apartment?
    init(name:String, address:String) {
        self.name = name
        self.address = address
    }
    deinit {
        debugPrint("Person class - Deinit method called")
    }
}

class Apartment {
    var name:String
    var personDetails:Person?
    init(name:String) {
        self.name = name
    }
    deinit {
        debugPrint("Apartment class - Deinit method called")
    }
}

var person:Person?
var apartment:Apartment?
person = Person.init(name: "John", address: "CA")
apartment = Apartment.init(name: "My Apartment")

person?.apartment = apartment
apartment?.personDetails = person

person = nil

apartment = nil

Are you getting shocked why deinit function not getting called. Welcome to retain cycle concept.

Even though you are making class instance to nil, both class instance parameters (apartment and personDetails) having strong reference with each other. whenever you create the instance or assigning the instance to some other variable it will create a strong reference.

Now the challenge is to break this retain cycle to deinitialize the classes from memory. How can we achieve this?

Just add weak keyword before the apartment variable.

class Apartment {
    var name:String
    weak var personDetails:Person?
    init(name:String) {
        self.name = name
    }
    deinit {
        debugPrint("Apartment class - Deinit method called")
    }
}

That's it. Now automatically both classes will remove from memory.

Weak Self vs Unowned Self:

Like class, closures also reference type. So, when you are accessing any Self instance params inside the closures, it will create the strong reference. To avoid this, we need to use either weak self or unowned self.

Both unowned and weak kind of optional, but weak variable initialised with nil. But unowned must have non-nil values. You have to use unowned, only if you know that the instance definitely will be there in memory. If you try to access the self variable after it released from memory your app will crash. So, better to use weak self inside the closures. Lets see one example to understand this better.

class ViewController:UIViewController {
    var name:String = "David!"
    override func viewDidLoad() {
        super.viewDidLoad()
        print(printNameWithHello())
    }
    
    private func printNameWithHello() -> String {
        let signature:String = { [weak self] in
            guard let string = self?.name else { fatalError("Unable to access name")}
                return "Hello" + string
        }()
        return signature
    }
}

The example I have given above is just for your understanding. Here the function is safe, because closure can't access the Self variable name if it is not in memory.

class ViewController:UIViewController {
    var name:String = "David!"
    override func viewDidLoad() {
        super.viewDidLoad()
        print(printNameWithHello())
    }
    
    private func printNameWithHello() -> String {
        let signature:String = { [unowned self] in
                return "Hello" + self.name
        }()
        return signature
    }
}

See the above unowned self example, it will try to access the value from memory even after it got released. So, app will be crash. Here you can't check self.name != nil because it is non-optional value.

Hope you understand about Retain cycle and the difference between weak self and unowned self.

!! Happy Coding !! :)

4 comments: