Weak references? Strong references? Not held? The amount of God--Swift Reference Counting Guide

Source: Internet
Author: User
Tags closure

ARC

The compile time feature of the automatic memory management of the ARC Apple version. It represents the automatic reference count (Automatic Reference counting). That is, for an object, memory is freed only if the reference count is 0.

Strong (strong reference)

Let's start with what is a strong quote. It is essentially a generic reference (pointer, and so on), but it is unique in that it is able to protect the object by making the object's reference count + one, avoiding the reference object being destroyed by the arc mechanism. Essentially, any object that has a strong reference will not be destroyed. Remember this is important for other knowledge such as the reference loop that I'm going to talk about next.

Strong references are everywhere in Swift. In fact, when you declare a property, it defaults to a strong reference. In general, it is safe to use strong references when the relationship between objects is linear. Strong references are usually OK when strong references between objects flow from the parent level to the child hierarchy.

Here are some examples of strong references

123456789 class Kraken {    let tentacle = Tentacle() //strong reference to child.}class Tentacle {    let sucker = Sucker() //strong reference to child}class Sucker {}

The sample code shows a linear relationship. Kraken has a strong reference to the tentacle instance object, and tentacle has a strong reference to the sucker instance object. The reference relationship flows from the parent level (Kraken) to the child level (sucker).

Similarly, in animation blocks, reference relationships are similar:

123 UIView.animateWithDuration(0.3) {    self.view.alpha = 0.0}

Since animatewithduration is a static method of UIView, the closure here acts as a parent level, self as a sub-level.

So what happens when a sub-level wants to refer to the parent hierarchy? Here we are going to use weak and unowned to quote.

Weak and unowned references

Weak

The weak reference does not protect the referenced object from being destroyed by the arc mechanism. A strong reference can make the reference count of the referenced object +1, and the weak reference does not. In addition, if the weakly referenced object is destroyed, the weak reference pointer is emptied. This ensures that when you invoke a weak reference object, you can get an object or nil.

In Swift, all weak references are a very small number of optional types (vs. var and let), because weak reference objects can and will become nil when there is no strong reference to the object reference.

For example, such a code would not compile

123 class Kraken {    weak let tentacle = Tentacle() //let is a constant! All weak variables MUST be mutable.}

Because Tentacle is a let constant. Let constants cannot be changed while they are running. Because weak reference variables become nil without being strongly referenced, the Swift compiler requires you to use Var to define weak reference objects.

It is important to note that using weak reference variables prevents you from having a possible reference loop. A reference loop occurs when two objects are strongly referenced to each other. If 2 objects refer to each other, arc cannot emit the appropriate release information for both objects because the two objects are interdependent with each other. is an official concise picture from Apple, it's a good explanation for this situation:

A more appropriate example is to inform APIs and look at the following code:

1234567891011121314 class Kraken {    varnotificationObserver: ((NSNotification) -> Void)?    init() {        notificationObserver = NSNotificationCenter.defaultCenter().addObserverForName("humanEnteredKrakensLair", object: nil, queue: NSOperationQueue.mainQueue()) { notification in            self.eatHuman()        }    }        deinit {        ifnotificationObserver != nil {            NSNotificationCenter.defaultCenter.removeObserver(notificationObserver)        }    }}

In this case we have a reference loop. You will find that the closure in swift behaves similar to Objective-c's blocks. If you declare a variable outside the scope of the closure, a second strong reference is generated to the variable when it is used in the closure. The only exceptions are variables that use value types, such as Ints, Strings, arrays, and dictionaries in Swift.

Here, when you call Eathuman (), Nsnotificationcenter retains a closure that captures self in a strongly quoted manner. Experience tells us that you should clear the notification listener object in the Deinit method. The problem with this code is that we didn't erase the block until deinit. But Deinit is never called by the arc mechanism because the closure has a strong reference to the Kraken instance.

This situation may also occur in Nstimers and Nsthread.

The way to resolve this situation is to use a weak reference to self in the capture list of the closure. This will break the strong reference loop. So, our object reference graph will look like this:

Turning self into weak does not make the self reference count +1, so the arc mechanism can release the object at the right time.

To use weak and unowned variables in closures, you should surround them with []. Such as:

123 let closure = { [weak self] in    self?.doSomething() //Remember, all weak variables are Optionals!}

In the above code, why do you want to put weak self in square brackets? It looks so funny! In Swift, we see that the square brackets think of arrays. You know what? You can define multiple capture values within a closure! For example:

1234 let closure = { [weak self, unowned krakenInstance] in//Look at that sweet Array of capture values.    self?.doSomething() //weak variables are Optionals!    krakenInstance.eatMoreHumans() //unowned variables are not.}

It looks more like an array, doesn't it? Now you know why you put the captured value in square brackets. So with what we already know, by adding [weak self] in the closure capture list, we can resolve the previous notification code that has a reference loop.

123 NSNotificationCenter.defaultCenter().addObserverForName("humanEnteredKrakensLair", object: nil, queue: NSOperationQueue.mainQueue()) { [weak self] notification in//The retain cycle is fixed by using capture lists!    self?.eatHuman() //self is now an optional!}

Other things we use with weak and unowned variables are when you use protocols to implement proxies between multiple classes, because the classes in swift use reference semantics. In Swift, structs and enumerations can follow the same protocol, but they use value semantics. If a parent class like this takes a subclass with a delegate that uses the proxy:

12345678910111213141516171819202122 class Kraken: LossOfLimbDelegate {    let tentacle = Tentacle()    init() {        tentacle.delegate = self    }        func limbHasBeenLost() {        startCrying()    }}protocol LossOfLimbDelegate {    func limbHasBeenLost()}class Tentacle {    vardelegate: LossOfLimbDelegate?         func cutOffTentacle() {        delegate?.limbHasBeenLost()    }}

Here we need to use the weak variable. In this case, Tentacle has a strong reference to Kraken in the form of a proxy attribute, and Kraken has a strong reference to tentacle in its tentacle attribute. We solve this problem by adding weak to the proxy declaration:

1 weak vardelegate: LossOfLimbDelegate?

Is it possible to find that writing cannot be compiled? cannot be compiled because a non-class type of protocol cannot be identified as weak. Here, we must let the protocol inherit: class, thus using a class protocol to mark the proxy attribute as weak.

123 protocol LossOfLimbDelegate: class { //The protocol now inherits class    func limbHasBeenLost()}

When do we use: class, through Apple's official documentation:

"Use a class-only protocol if the behavior defined by, protocol ' s requirements assumes or requires that a conforming Type has reference semantics rather than value semantics. "

Essentially, when you have the same referential relationships as I did above, you use: class. In the case of structs and enumerations, it is not necessary to use: class, because structs and enumerations are value semantics, and classes are reference semantics.

unowned

Weak references and unowned references are somewhat similar but not identical. unowned references, like weak references, do not increase the reference count of the object. However, in Swift, a unowned reference has the advantage of having a non-optional type. This is easier to manage than with the use of optional binding. This differs from the implicit optional type (implicity unwarpped optionals). In addition, the unowned reference is non-zeroing (nonzero), which means that when an object is destroyed, the object it directs is not zeroed. That is, using unowned references may cause dangling pointers (wild pointer URL) in some cases. Do you think like me? When using Objective-c, the unowned reference is mapped to the unsafe_unretained reference. http://www.krakendev.io/when-to-use-implicitly-unwrapped-optionals/

See if there is a bit of egg ache here. Since both weak and unowned references do not increase the reference count, they can be used to dereference loops. So what are we going to do with them? According to Apple Documentation:

"Use a weak reference whenever it was valid for the reference to become nil at the some point during its lifetime. Conversely, use a unowned reference when you know the reference would never be nil once it had been set during Initia Lization. "

Translation: In the life cycle of a reference object, if it may be nil, then use the weak reference. Conversely, when you know that the reference object will never be nil after initialization, use unowned.

Now you know: like implicitly unwrapped optional (implicitly optional type), if you can guarantee that the reference object will not be nil during use, use unowned. If not, then use weak.

Here's a good example. The closure in Class captures the self,self never nil.

123456789101112 class RetainCycle {    varclosure: (() -> Void)!    varstring = "Hello"    init() {        closure = {            self.string = "Hello, World!"        }    }}//Initialize the class and activate the retain cycle.let retainCycleInstance = RetainCycle()retainCycleInstance.closure() //At this point we can guarantee the captured self inside the closure will not be nil. Any further code after this (especially code that alters self‘s reference) needs to be judged on whether or not unowned still works here.

In this case, the self is captured in the strong reference form of the packet, and self is also retained by the closure property by a strong reference to the closure, which is a reference loop. Just add [unowned self] to the closure to break the reference loop:

123 closure = { [unowned self] in    self.string = "Hello, World!"}

In this case, since we called the closure immediately after initializing the Retaincycle class, we can assume that self will never be nil.

Apple also explains this in unowned references:

"Define a capture in a closure as an unowned reference when the closure and the instance it captures would always refer to Each of the other, and is always being deallocated at the same time. "

If you know that the objects you refer to are released at the right time, and they are interdependent, and you don't want to write some extra code to empty your reference pointers, you should use unowned references instead of weak references.

Like this lazy loading in closures using self is a good example of using unowned:

123456 class kraken {      let petname =   "Krakey-poo"      LAZY  var   businesscardname:  ()  -> string = { [unowned self]   in           return   "mr. kraken  aka  "  + self.petname       } }

We need to use unowned self to avoid reference loops. Kraken and Businesscardname hold each other in their life cycle. They hold each other and are therefore always destroyed at the same time, satisfying the conditions for using unowned.

However, do not confuse the following lazy load variable with the closure:

123456 < Code class= "JS plain" >class kraken { &NBSP;&NBSP;&NBSP;&NBSP; Code class= "JS plain" >LET&NBSP;PETNAME&NBSP;=&NBSP; "Krakey-poo" &NBSP;&NBSP;&NBSP;&NBSP; LAZY&NBSP; var  businesscardname: string = {          return   "mr. kraken aka "  + self.petname &NBSP;&NBSP;&NBSP;&NBSP; } () }

When calling closure in a lazy load variable, there is no need to add unowned self because there is no retain closure. The variable simply assign the result of the closure to itself, and the closure is immediately destroyed when it is used. The following is a good proof of this. (is a copy of the thick-skinned comment area алексей)

Summarize

Reference loops very pit daddy! But careful code, clear your reference logic, by using weak and unowned can be good to avoid memory loops and memory leaks. I hope this guidebook will help you.

Weak references? Strong references? Not held? The amount of God--Swift Reference Counting Guide

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.