Initial Swift Language learning note 6 (arc-own active reference count, memory management)

Source: Internet
Author: User



Author: fengsh998 Original address:http://blog.csdn.net/fengsh998/article/details/31824179 Reprint Please indicate the source Suppose that the article is helpful to you. Please support me by leaving a message or following the public account fengsh998 , thank you.






Swift uses its own active reference count (ARC) to manage the memory usage of the application. This means that memory management is already part of Swift, and in most cases you do not need to consider memory management.



When the instance is no longer needed. ARC will voluntarily release the memory used by these instances themselves.



Another thing to note:



The reference count acts only on the class instance. Structs and enumerations are value types, not reference types. So it cannot be referenced for storage and delivery.






Swift's ARC work process



Whenever you create an instance of a class. Arc allocates a memory block to store the information for this instance, including the type information and the attribute value information for the instance .



In addition, when the instance is no longer in use, ARC releases the memory occupied by the instance, which can be used again.
However, assuming that ARC releases the instance being used, it is no longer possible to access the instance properties. Or invoke the method of the instance. Direct access to this instance can cause the application to crash.



Just like an empty instance or a free instance.




To ensure that instances exist when an instance is required. For each class instance, ARC tracks how many properties, constants, and variables point to these instances. ARC does not release this instance when an active reference points to it.
To achieve this. When you assign a class instance to a property , constant , or variable . A strong reference to the instance (strong reference) will be constructed. Known as a strong reference is because it holds this instance stably, and when the strong reference exists, the instance cannot be released on its own initiative and is therefore safe to use.



Examples:





class Teacher
{
     var tName: String

     init (name: String)
     {
         tName = name
         println ("The teacher \ (tName) instance is initialized.")
     }
    
     func getName ()-> String
     {
         return tName
     }
    
     func classing ()
     {
         println ("Teacher \ (tName) is giving a lecture to students.")
     }
    
     deinit
     {
         println ("Teacher \ (tName) instance is destructed.")
     }
}
Test arc:







func testArc ()
{
     var teacher: Teacher? = Teacher (name: "张三") // Instancing a Teacher object will point to a variable, and a strong reference is generated at this time (as if the reference count in OC + 1)
     var refteacher: Teacher? = teacher // A strong reference is generated again (reference count again + 1)
     var refteacher2: Teacher? = teacher // A strong reference is generated again (the reference count is then +1)

    
     refteacher = nil // The first reference object is nil and does not release the instance, (reference count -1)
     teacher? .classing () // Normal
     teacher = nil // The second reference object is nil and does not release the instance, (reference count -1)
     refteacher2! .classing () // Normal
     refteacher2 = nil // The third reference object is nil. At this time, no reference has been made, so ARC is recycled and the instance is released. (Reference count-1) The last reference count is 0. Destructuring
     refteacher2?
.classing () // No more output
}







Output Result:





Teacher Zhang San The instance is initialized.
Teacher Zhang San is giving a lecture to students.
Teacher Zhang San is giving a lecture to students.
Teacher Zhang San has finished destructing the instance.





from the example above, it is true that Swift gives us the active management of memory, and developers do not have to consider too much memory management. But is that really the case? Is it really safe? How do you use arc as a developer?


Although arc reduces the amount of memory management work, ARC is not completely secure. Take a look at the memory leak that the cyclic strong reference leads to.






Examples:





class Teacher
{
    var tName: String
    var student: Student?
       // Add student objects, initially nil
    
    init (name: String)
    {
        tName = name
        println ("The teacher \ (tName) instance is initialized.")
    }
    
    func getName ()-> String
    {
        return tName
    }
    
    func classing ()
    {
        println ("Teacher \ (tName) is giving students \ (student?

.getName ()) Lecture. ")
    }
    
    deinit
    {
        println ("Teacher \ (tName) instance is destructed.")
    }
}

class Student
{
    var tName: String
    var teacher: Teacher? // Add teacher object, initially nil
    
    init (name: String)
    {
        tName = name
        println ("Student \ (tName) instance is initialized.")
    }
    
    func getName ()-> String
    {
        return tName
    }
    
    func listening ()
    {
        println ("Student \ (tName) is listening to \ (teacher? .getName ()) teacher lecture")
    }
    
    deinit
    {
        println ("Student \ (tName) instance destructuring is complete.")
    }
}




Test leak:







func testMemoryLeak ()
{
     var teacher: Teacher?
     var student: Student?

    
     teacher = Teacher (name: "陈峰") // (Reference count is 1)
     student = Student (name: "Xu Ge") // (Reference count is 1)
    
     teacher! .student = student // After the assignment, a strong reference to the "student" object will be generated (reference count + 1)
     student! .teacher = teacher // After the assignment, a strong reference to the "teacher" object will be generated (reference count + 1)
    
     teacher! .classing () // Since I know clearly that the teacher object cannot be empty, I use! Unpack
     student! .listening ()
    
     // The following code. Writing or not writing can't release the object
     teacher = nil // reference count-1 but not yet = 0, so it will not be destructed
     student = nil // reference count -1 but not yet 0, so it will not be destructed
    
     println ("Output after release")
    
     teacher? .classing () // Because I can't determine whether the teacher object is empty, I must use? to access it.
     student? .listening ()
    
}

Output Result:







Teacher Chen Feng The instance is initialized.
Student Xu Ge instance is initialized.
Teacher Chen Feng is giving a lecture to student Xu Ge.
Student Xu Ge is listening to the lecture given by Mr. Chen Feng
Output after release

Deinit was not called from beginning to finish. As a result, it is no longer possible to take any measures to release the two objects, only the end of the life cycle of the app.





The mutual reference between instances, in daily development is a common one, how to avoid such a cyclic strong reference caused by the memory leak ?



The ability to resolve the problem of strong reference loops by defining a weak reference (weak) or a non-host referenced (unowned) variable between classes



Weak reference mode:



A weak reference does not maintain a strong hold of the object being referred to. Therefore, ARC does not prevent the collection of reference instances. This feature guarantees that a reference is not part of a strong reference loop. Indicates that a reference to a weak reference is preceded by a keywordweak in the life attribute or variable.






Attention
Weak references must be declared as variables , indicating that their values can be changed at run time.



A weak reference cannot be declared as a constant .




Because a weak reference can have no value, you must declare a weak reference to be an optional type. The optional type makes it possible to have no values in swift.



Therefore, it is only necessary to use the above example as an instance variable before adding weak keyword to it, such as:





weak var student : Student?
or
    weak var teacher : Teacher?





To come down and test the weak var student:student? When set to a weak reference, the time point at which the test is released (condition one)





    var teacher:teacher?var teacher: Teacher?

     var student: Student?
    
     teacher = Teacher (name: "陈峰")
     student = Student (name: "Xu Ge")
    
     teacher! .student = student // After the assignment, a strong reference to the "student" object will be generated
     student! .teacher = teacher // After the assignment, a strong reference to the "teacher" object will be generated
    
     teacher! .classing ()
     student! .listening ()
    
     teacher = nil // destructor will not be called immediately at this time, it will not be released until student release
     // student = nil
    
     println ("Output after release")
    
     teacher?

.classing () // It was set to nil before, so there is no output
     student? .listening ()


Tested Output:




Teacher Chen Feng The instance is initialized. // Run teacher = Teacher (name: "陈峰")
Student Xu Ge instance is initialized. // Run student = Student (name: "Xu Ge")
Teacher Chen Feng is giving a lecture to student Xu Ge. // Run teacher! .Classing ()
Student Xu Ge is listening to the lecture given by Mr. Chen Feng // Run student! .Listening ()
Output after release // Run println ("Output after release")
Student Xu Ge is listening to a lecture by Chen Feng // Run student? .Listening ()
Student Xu Ge The destructuring of the instance is completed. // The student object is released first
Teacher Chen Feng The instance is destructed. // At this time, because the student object is released, there is no reference at this time, and the destruction can be performed






Suppose weak var teacher:teacher?



To test again: (case two)





var teacher: Teacher?
     var student: Student?
    
     teacher = Teacher (name: "陈峰")
     student = Student (name: "Xu Ge")
    
     teacher! .student = student // After the assignment, a strong reference to the "student" object will be generated
     student! .teacher = teacher // After the assignment, a strong reference to the "teacher" object will be generated
    
     teacher! .classing ()
     student! .listening ()
    
     teacher = nil // destructor will not be called immediately at this time, it will not be released until student release
     // student = nil
    
     println ("Output after release")
    
     teacher? .classing ()
     student?
.listening () // This is not due to


Output Result:







Teacher Chen Feng The instance is initialized.
Student Xu Ge instance is initialized.
Teacher Chen Feng is giving a lecture to student Xu Ge.
Student Xu Ge is listening to the lecture given by Mr. Chen Feng
Teacher Chen Feng's case analysis is complete.
Output after release
Student Xu Ge is listening to a lecture by teacher Nil
Student Xu Ge's case is destructurized.

The test concludes that:





When the Class A has a weakly referenced instance of Class B, and at the same time a strongly quoted instance of a is present in class B, it is assumed that a is released and does not affect the B's disjunction. However, the memory recovery of a will be sufficient to recover after the instance of B is released. (Result of the situation one)



When a class is wrapped in a strongly referenced instance of Class B, assuming A is released, it does not affect the B's disjunction. (Result of the situation two)


non-host reference mode:


Is the same as a weak reference. A no-host reference does not hold a strong reference to the instance.



But unlike weak references. A non-host reference usually has a value . So. A no-host reference is not defined as an optional type . Indicates that a non-host reference is preceded by a keywordunownedwhen the property or variable is declared .
Because the no-host reference is not an optional type . So you don't have to use it every time you use a no-host reference?



。 A non-host reference is usually directly accessible. However, when a non-host reference refers to an instance being disposed. Arc does not set the reference value to nil. The non-optional type cannot be set to nil.
Attention
After a non-host reference to the instance is freed, suppose you want to access the non-host reference, which will trigger a run-time error (use no-host reference only if you can confirm that a reference always points to an instance).



Such a situation in Swift can also cause the application to crash, with some unpredictable behavior occurring.



Therefore, special care should be taken when using it.




Change the previous sample to a no-host reference:





class Teacher
{
    var tName: String
    var student: Student? // A strong reference to the student object, the instance can be nil
    
    init (name: String)
    {
        tName = name
        println ("The teacher \ (tName) instance is initialized.")
    }
    
    func getName ()-> String
    {
        return tName
    }
    
    func classing ()
    {
        println ("Teacher \ (tName) is giving a lecture to student \ (student? .getName ()).")
    }
    
    deinit
    {
        println ("Teacher \ (tName) instance is destructed.")
    }
}

class Student
{
    var tName: String
    unowned var teacher: Teacher // No host reference, cannot be set to nil
    
    init (name: String, tcher: Teacher)
    {
        tName = name
        teacher = tcher // Cannot be made optional due to hostless references. Must be initialized
        println ("Student \ (tName) instance is initialized.")
    }
    
    func getName ()-> String
    {
        return tName
    }
    
    func listening ()
    {
        println ("Student \ (tName) is listening to \ (teacher.getName ()) teacher lecture")
    }
    
    deinit
    {
        println ("Student \ (tName) instance destructuring is complete.")
    }
}

Test without a host reference:







func testNotOwner ()
{
     var teacher: Teacher? // Declares optional variables
    
     teacher = Teacher (name: "陈峰")
    
     var student = Student (name: "Xu Ge", tcher: teacher!)
    
     // Make mutual references
     teacher! .student = student
     student.teacher = teacher!
    
     teacher! .classing ()
     student.listening ()
    
     teacher = nil
     println ("After the teacher object is released")
    
     teacher?
.classing ()
     student.listening () // error Because when the previous teacher was set to nil, the student object was implicitly released. So if you visit here again, it will crash
}



Output Result:







Teacher Chen Feng The instance is initialized.
Student Xu Ge instance is initialized.
Teacher Chen Feng is giving a lecture to student Xu Ge.
Student Xu Ge is listening to the lecture given by Mr. Chen Feng
Teacher Chen Feng's case analysis is complete.
After the teacher object is released
Program ended with exit code: 9 (lldb) // will crash, thead1: Exc_BREAKPOINT (code = EXC_i386_BPT, subcode = 0x0)
So when using a non-host reference, you need to be very careful. Be careful when someone releases a strong reference object by releasing it. So it doesn't affect the original instance if you want to release them. The ability to use weak references will not affect even nil.








As described above, when an instance object in a class is assumed to be an instance of nil for a certain time throughout the life cycle, using weak references, it is assumed that an instance of the entire life cycle, once constructed, cannot be set to a nil instance variable. A non-host reference is typically used. But there was some time. Mutual reference properties in two classes are always valued and cannot be set to nil. In such cases, it is common to set an instance of a class to be a no-host property. The instance variable in the other class is set to the implicitly boxed optional attribute (that is, the! Number property)



Examples are as follows. Every father has a child (No child can call a father?) ), every child has a biological father





class Father
{
     let children: Children! // Declared as implicit optional
     let fathername: String
     init (name: String, childName: String)
     {
         self.fathername = name
         self.children = Children (name: childName, fat: self) // Mutual references are generated during initialization
     }
    
     deinit
     {
         println ("father deinited.")
     }
}

class Children
{
     unowned let father: Father // Declared as a hostless type
     let name: String
     init (name: String, fat: Father)
     {
         self.name = name
         self.father = fat
     }
    
     deinit
     {
         println ("children deinited.")
     }
}

Test code:







var fa = Father (name: "Wang Wu", childName: "Wang Ba")
     println ("\ (fa.fathername) has a child called \ (fa.children.name)")

Output Result:







Harry has a child called Wang eight father Deinited.children deinited.
The same can be seen, although the circular reference, but still can be recovered normally.





In another case, a strong reference to itself (self) for its own closure can also lead to a memory leak.






Examples:





class CpuFactory
{
    let cpuName: String
    let cpuRate: Double
    init (cpuName: String, rate: Double)
    {
        self.cpuName = cpuName
        self.cpuRate = rate
    }
    
    // Declaring a closure
    @lazy var someClosure: (Int, String)-> String = {
        // The following sentence cannot be stared.The compiler will report Tuple types ‘(Int, String)‘ and ’()‘ hava a different number of elements (2 vs. 0)
        [unowned self] (index: Int, stringToProcess: String)-> String in
        // closure body goes here
        
        return "A \ (self.cpuName)" // reference self in the closure
    }
    
    // Declare a closure, refer to self in the same closure
    @lazy var machining: ()-> String = {
        [unowned self] in // This sentence can be stared at (according to the book. Using this sentence can explain the strong reference of closures, but personal practice. Whether you add this sentence or not, it will not be released. That is to say, there is a memory leak )
        // closure body goes here
        
        if self.cpuRate> 10
        {
            return "\ (self.cpuName) i7 2.5G"
        }
        else
        {
            return "\ (self.cpuName) i3 2.0G"
        }
    }
    
    // Declare a closure, but pass itself as a parameter in the closure (to avoid memory leaks)
    @lazy var machining2: (CpuFactory)-> String = {

        [unowned self] (cpu: CpuFactory)-> String in
        
        if cpu.cpuRate> 10
        {
            return "\ (cpu.cpuName) i7 2.5G"
        }
        else
        {
            return "\ (cpu.cpuName) i3 2.0G"
        }
    }
    
    deinit
    {
        println ("Cpu Factroy is deinited.")
    }
}

In this example there are three closures, each of which is a participant. And without participation, the [unowned Self] (paramers) in operation cannot be omitted for the participant. Otherwise it compiles just. Other than that. It is not mentioned in the book that only the @lazy of the closure of the ability to use [unowned self] otherwise in the ordinary closure of the use will also error.





Another point of the book is that when self is used in its own closure, a strong reference is generated. To the memory leak, so adding [unowned self] in this sentence can destroy such a strong reference, so that the memory is freed, but I personally verify, even if added and not released.









Test:





func testClosure()
{
    var cpu : CpuFactory? = CpuFactory(cpuName: "Core",rate: 5)
//    println(cpu!.machining())
    println(cpu!.machining2(cpu!))
//    println(cpu!.someClosure(3,"hello"))
    
    cpu = nil
}
Individually verify the output of each sentence separately:







func testClosure()
{
    var cpu : CpuFactory?

= CpuFactory(cpuName: "Core",rate: 5) println(cpu!.machining()) cpu = nil }


Output:







Core i3 2.0G
Obviously CPU = Nil also does not release memory.





Take another look at the second one.





func testClosure()
{
    var cpu : CpuFactory? = CpuFactory(cpuName: "Core",rate: 5)
    println(cpu!.machining2(cpu!))
    cpu = nil
}
Output
Core i3 2.0GCpu Factroy is deinited.
It is possible to release memory when using itself as a reference.






The same again test Third kind:








func testClosure()
{
    var cpu : CpuFactory? = CpuFactory(cpuName: "Core",rate: 5)
    println(cpu!.someClosure(3,"hello"))
    cpu = nil
}
Output
A Core
In fact the third and the first kind are the same, all quoted self. But the first one can test the [unowned self]in and stare without staring, and can find the result is the same. does not release memory.








It's a little confusing .....



















Copyright notice: This article Bo Master original articles, blogs, without consent may not be reproduced.






Initial Swift Language learning note 6 (arc-own active reference count, memory management)


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.