A strong reference ring generated by closures

Source: Internet
Author: User
Tags closure instance method
a strong reference ring generated by closuresWe have seen how strong reference loops are generated, and how to introduce weak and unowned references to break reference loops.

Assigning a closure to a property of a class instance, and the closure uses an instance, also produces a strong reference ring. The closure may have access to an attribute of the instance, such as Self.someproperty, or a method that invokes an instance, such as Self.somemethod. Both of these situations result in the closure using self, resulting in a grab-reference loop.

Because a closure such as a class is a reference type, it causes a strong reference ring. When you assign a closure to a property, you also assign a reference to the closure. In essence, the problem described earlier is the same-two strong references keep each other valid. However, unlike two class instances, this one is a class instance and the other is a closure.

Swift offers an elegant way to solve this problem, which we call the closure occupancy list (Closuer capture). Again, before you learn how to avoid a strong reference ring from a closed list, take a look at how the grab ring is generated.

The following example will show you how to generate a grab reference ring when a closure references self. This example tops a class named HtmlElement to model a separate element in HTML:
Class HtmlElement {Let name:string let text:string. @lazy var ashtml: ()-> String = {if let text = self.text {ret Urn "<\ (self.name) >\ (text) </\ (self.name) >"} else {return "<\ (self.name)/>"} init (Name:string, Tex T:string? = nil) {self.name = name Self.text = text} deinit {println ("\ (name) is being deinitialized")} class HtmlElement defines a name Sex to represent the name of the element, such as "P" representing the paragraph, or "BR" representing the newline, and an optional property text that sets the text for the HTML element.

In addition to the two attributes above, HtmlElement also defines a lazy property ashtml. This property refers to a closure that synthesizes the name and text groups into an HTML string fragment. The property is ()-> string type, which is "a function that returns a string without arguments."

By default, the closure is assigned to the Ashtml property, which returns a string representing the HTML tag. If the text value exists, the label contains the optional value text, or does not contain text. For a paragraph, the closure returns either "<p>some text</p>" or "<p/>", depending on whether text is "some text" or "nil".

You can name and use ashtml like an instance method. However, since ashtml is ultimately a closure rather than an instance method, you can replace the default value with a custom closure if you change the HTML processing of a particular element.
Note: Ashtml is declared as a lazy property, because ashtml is required only if the element does need to be processed as a string of HTML output. That is, self is available in the default closure, because the lazy property can be accessed only if the initialization is complete and self does exist. HtmlElement has only one initialization function that initializes an element based on the name and text (if any) arguments. The class also defines a deinitializer that prints a message when the HtmlElement instance is destroyed.

The following code creates a HtmlElement instance and prints the message.
var paragraph:htmlelement? = HtmlElement (name: "P", Text: "Hello, World") println (paragraph!. Ashtml ())//print "<p>hello, world</p>" Note that the paragraph variable above is defined as optional htmlelement, so we can assign a value nil give it to demonstrate the strong reference ring. Unfortunately, the HtmlElement class produces a strong reference ring between the class instance and the closure of the ashtml default value. As shown in the following illustration:


The Ashtml property of the instance holds a strong reference to the closure.

However, the closure uses self (referencing Self.name and Self.text), so the closure occupies self, which means that the closure also holds a strong reference to the HtmlElement instance. This creates a strong reference ring. (Please refer to capturing values) for more information about the value of closures.
Note: Although the closure uses self more than once, it occupies only one strong reference to the HtmlElement instance. If you set paragraph to nil and break a strong reference to the HtmlElement instance that it holds, the HtmlElement instance and its closures will not be destroyed because of the strong reference ring:
Paragraph = nil Note that the message in Htmlelementdeinitializer does not print, confirming that the HtmlElement instance has not been destroyed.
resolving the strong reference ring generated by closuresA strong reference ring between closures and class instances can be resolved by defining the possession list as part of the closure when defining closures. The possession list defines a rule that occupies one or more reference types within a closure. As with a strong reference ring that resolves between two class instances, declaring each possessive reference to be a weak or unowned reference, rather than a strong reference. Depending on the code relationship, you decide whether to use weak references or no primary references.
Note: Swift has the following constraints: As long as the member of Self is used in the closure, it is necessary to use Self.someproperty or self.somemethod (rather than just someproperty or somemethod). This can be a reminder that you may be inadvertently occupying self. Define Possession listEach element in the possession list is made up of references to weak or unowned keywords and instances, such as self or someinstance. Each pair is in curly braces, separated by commas.

The possession list is placed before the closure parameter list and the return type:
@lazy var someclosure: (Int, String)-> string = {[unowned self] (index:int, stringtoprocess:string)-> string in Closure body goes here} if the closure does not specify a parameter list or return type (which can be inferred by context), then the possession list is placed where the closure begins, followed by the keyword in:
@lazy var someclosure: ()-> String = {[unowned self] in//closure body goes here} weak references and unowned referencesWhen closures and instances of possession are always referenced to each other and are always destroyed at the same time, the possession within the closure is defined as an unowned reference.

Conversely, when a possessive reference may sometimes be nil, the possession within the closure is defined as a weak reference. A weak reference is always an optional type, and when the referenced instance is destroyed, the value of the weak reference is automatically set to nil. With this feature, we can check if they exist in the closure.
Note: If the referenced reference is never set to nil, you should use a unowned reference instead of a weak reference. In the HtmlElement example mentioned earlier, a unowned reference is the correct way to resolve a strong reference. This encodes the HtmlElement class to avoid strong reference loops:
Class HtmlElement {Let name:string let text:string? @lazy var ashtml: ()-> String = {[unowned self] in if let text = self.text {return ' <\ (self.name) >\ (text) </\ (self.name) > "} else {return" <\ (self.name)/> "}" init (name:string, text:string? = nil) {self.name = name Self.text = text} deinit {println ("\ (name) is being deinitialized")} The HtmlElement implementation above is the same as the previous implementation, but it is more Possession list. Here, the possession list is [unowned self], which means "to occupy self with a unowned reference instead of a strong reference."
As before, we can create and print HtmlElement instances:
var paragraph:htmlelement? = HtmlElement (name: "P", Text: "Hello, World") println (paragraph!. ASTHML ())//print "<p>hello, world</p>" using the possession list after the reference relationship as shown in the following figure:

This time, the closure holds self in the form of a unowned reference and does not hold a strong reference to the HtmlElement instance. If the assignment is paragraph as an nil,htmlelement instance, it will be destroyed and will be able to see its deinitializer printed message.
Paragraph = nil//print "P is being deinitialized"

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.