美文网首页
swift-自动引用计数器

swift-自动引用计数器

作者: Zz橙淞 | 来源:发表于2017-04-11 22:04 被阅读0次
/*
     • 自动引用计数的工作机制
     • 自动引用计数实践
     • 类实例之间的循环强引用
     • 解决实例之间的循环强引用
     • 闭包引起的循环强引用
     • 解决闭包引起的循环强引用
     
     */
    
    //自动引用计数器的工作机制
    /*当你每次创建一个类的新的实例的时候,ARC 会分配一块内存来储存该实例信息。内存中会包含实例的类型信 息,以及这个实例所有相关的存储型属性的值。
    此外,当实例不再被使用时,ARC 释放实例所占用的内存,并让释放的内存能挪作他用。这确保了不再被使用的 实例,不会一直占用内存空间。
    然而,当 ARC 收回和释放了正在被使用中的实例,该实例的属性和方法将不能再被访问和调用。实际上,如果你 试图访问这个实例,你的应用程序很可能会崩溃。
    为了确保使用中的实例不会被销毁,ARC 会跟踪和计算每一个实例正在被多少属性,常量和变量所引用。哪怕实 例的引用数为1,ARC都不会销毁这个实例。
    为了使上述成为可能,无论你将实例赋值给属性、常量或变量,它们都会创建此实例的强引用。之所以称之
    为“强”引用,是因为它会将实例牢牢地保持住,只要强引用还在,实例是不允许被销毁的。*/
    
    //自动引用计数实践
    class Person {
    
        let name: String
        init(name: String) {
            self.name = name
            print("\(name) is being initialized")
        }
        deinit {
            print("\(name) is being deinitialized")
        }
        
    }
    
   // Person 类有一个构造函数,此构造函数为实例的 name 属性赋值,并打印一条消息以表明初始化过程生效。 on 类也拥有一个析构函数,这个析构函数会在实例被销毁时打印一条消息。
    var reference1: Person?
    var reference2: Person?
    var reference3: Person?
    
    reference1 = Person(name: "John Appleseed")
   // 应当注意到当你调用 Person 类的构造函数的时候, “John Appleseed is being initialized” 会被打印出来。由 此可以确定构造函数被执行。
    reference2 = reference1
    reference3 = reference1
    
    //如果你通过给其中两个变量赋值 nil 的方式断开两个强引用(包括最先的那个强引用),只留下一个强引用, rson 实例不会被销毁:
    reference1 = nil
    reference2 = nil
    //在你清楚地表明不再使用这个 Person 实例时,即第三个也就是最后一个强引用被断开时,ARC 会销毁它:
    
    reference3 = nil
    // 打印 “John Appleseed is being deinitialized”
    
    
    //类实例之间的循环引用
    //在上面的例子中,ARC 会跟踪你所新创建的 Person 实例的引用数量,并且会在 Person 实例不再被需要时销毁它。
    class Person1 {
    
        let name: String
        init(name: String) {
            self.name = name
        }
    var apartment: Apartment?
        deinit {
            print("\(name) is being deinitialized")
        }
    }
    
    class Apartment {
    
        let unit: String
        init(unit: String) {
            self.unit = unit
        }
       weak var tenant:Person1?
        deinit {
             print("Apartment \(unit) is being deinitialized")
        }
        
    }
    
    var john: Person?
    var unit4A: Apartment?
    
    john = Person(name: "John Appleseed")
    unit4A = Apartment(unit: "4A")
    
   // 不幸的是,这两个实例关联后会产生一个循环强引用。 Person 实例现在有了一个指向 Apartment 实例的强引 用,而 Apartment 实例也有了一个指向 Person 实例的强引用。因此,当你断开 john 和 unit4A 变量所持有的强 引用时,引用计数并不会降为 0 ,实例也不会被 ARC 销毁:
    john = nil
    unit4A = nil
    //注意,当你把这两个变量设为 nil 时,没有任何一个析构函数被调用。循环强引用会一直阻止 Person 和 Apartme nt 类实例的销毁,这就在你的应用程序中造成了内存泄漏。
    
    
    //解决实例之间的循环引用
    //弱引用:声明属性或者变量时,在前面加上 weak 关键字表明这是一个弱引用。
    
   // 然后跟之前一样,建立两个变量( john 和 unit4A )之间的强引用,并关联两个实例:
    
    
    //无主引用
    //和弱引用类似,无主引用不会牢牢保持住引用的实例。和弱引用不同的是,无主引用在其他实例有相同或者更长 的生命周期时使用。你可以在声明属性或者变量时,在前面加上关键字 unowned 表示这是一个无主引用。
    //重要
   // 使用无主引用,你必须确保引用始终指向一个未销毁的实例。
   // 如果你试图在实例被销毁后,访问该实例的无主引用,会触发运行时错误。
    
    class Customer {
    
        let name:String
        var card:CreditCard?
        init(name: String) {
            self.name = name
        }
        deinit {
            print("\(name) is being deinitialized")
        }
    }
    
        class CreditCard {
            let number:NSInteger
            unowned let customer: Customer
            init(number:NSInteger , customer: Customer) {
                self.number = number
                self.customer = customer
            }
            deinit {
                print("Card #\(number) is being deinitialized")
            
            }
        }
    
    var john1: Customer?
    john1 = Customer(name: "John Appleseed")
    john1!.card = CreditCard(number: 1234_5678_9012_3456, customer: john1!)

    
    //无主引用以及隐式解析可选属性
    //两个属性都必须有值,并且初始化完成后永远不会为 nil 。在这种场 景中,需要一个类使用无主属性,而另外一个类使用隐式解析可选属性。

    class Country {
    
        let name: String
        var capitalCity: City!
        init(name: String, capitalName: String) {
            self.name = name
            self.capitalCity = City(name: capitalName , country: self)
        }
    }
    
    class City{
    
        let name: String
        unowned let country:Country
        init(name: String ,country: Country) {
            self.name = name
            self.country = country
        }
        
    }
    
    //为了建立两个类的依赖关系, City 的构造函数接受一个 Country 实例作为参数,并且将实例保存到 country 属性。
    //Country 的构造函数调用了 City 的构造函数。然而,只有 Country 的实例完全初始化后, Country 的构造函数 才能把 self 传给 City 的构造函数
    //为了满足这种需求,通过在类型结尾处加上感叹号( City! )的方式,将 Country 的 capitalCity 属性声明为隐 式解析可选类型的属性。这意味着像其他可选类型一样, capitalCity 属性的默认值为 nil ,但是不需要展开它 的值就能访问它
   // 由于 capitalCity 默认值为 nil ,一旦 Country 的实例在构造函数中给 name 属性赋值后,整个初始化过程就完 成了。这意味着一旦 name 属性被赋值后, Country 的构造函数就能引用并传递隐式的 self 。 Country 的构造函 数在赋值 capitalCity 时,就能将 self 作为参数传递给 City 的构造函数。
    //以上的意义在于你可以通过一条语句同时创建 Country 和 City 的实例,而不产生循环强引用,并且 的属性能被直接访问,而不需要通过感叹号来展开它的可选值:
    var country = Country(name: "Canada", capitalName: "Ottawa")
    print("\(country.name)'s capital city is called \(country.capitalCity.name)")
    
    
    
    //闭包引起的循环引用
    //循环强引用还会发生在当你将一个闭包赋值给类实例的某个属性,并且这个闭包体中又使用了这个类实例时。这个闭包体中可能访问了实例的某个属性,例如 self.someProperty ,或者闭包中调用了实例的某个方法,例如 self.someMethod() 。这两种情况都导致了闭包“捕获” self ,从而产生了循环强引用。
    
    //循环强引用的产生,是因为闭包和类相似,都是引用类型。
    
    //下面的例子为你展示了当一个闭包引用了 self 后是如何产生一个循环强引用的。例子中定义了一个叫 t 的类,用一种简单的模型表示 HTML 文档中的一个单独的元素:
//        class HTMLElement {
//            let name: String
//            let text: String?
//            lazy var asHTML: (Void) -> String = {
//                
//                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 {
//                print("\(name) is being deinitialized")
//            }
//            
//        }
    
    //解决闭包引起的循环引用
    //只要在闭包内使用 self 的成员,就要用 self.someProperty 或者 self.someMethod() (而 不只是 someProperty 或 someMethod() )。这提醒你可能会一不小心就捕获了 self 。

    //定义捕获列表 
   // 捕获列表中的每一项都由一对元素组成,一个元素是 weak 或 unowned 关键字,另一个元素是类实例的引用(例如 self )或初始化过的变量(如 delegate = self.delegate! )。这些项在方括号中用逗号分开。
    //如果闭包有参数列表和返回类型,把捕获列表放在它们前面:
    
    //lazy var someClosure: (NSInteger ,String) -> String = {
    
      //  [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in // 这里是闭包的函数体
   // }
    
    //如果闭包没有指明参数列表或者返回类型,即它们会通过上下文推断,那么可以把捕获列表和关键字 in 放在闭包 最开始的地方:
    //lazy var someClosure: Void -> String = {
     //   [unowned self, weak delegate = self.delegate!] in // 这里是闭包的函数体
    //}
    
    //弱引用和无主引用

    //在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为 无主引用 。
    //相反的,在被捕获的引用可能会变为 nil 时,将闭包内的捕获定义为 弱引用 。弱引用总是可选类型,并且当引用 的实例被销毁后,弱引用的值会自动置为 nil 。这使我们可以在闭包体内检查它们是否存在。

    
    //前面的 HTMLElement 例子中,无主引/弱引用用是正确的解决循环强引用的方法。这样编写 HTMLElement 类来避免循环强 引用:
    class HTMLElement {
        let name: String
        let text: String?
        lazy var asHTML: (Void) -> String = {
           [unowned self] in//[weak 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 {
            print("\(name) is being deinitialized")
        }
    }

相关文章

  • swift-自动引用计数器

  • 自动引用计数器

    自动引用计数器 Auto Reference Count iOS 开发目前主流的内存管理方式, 就是让编译器来进行...

  • 关于内存管理

    首先明确一点什么是自动引用计数 自动引用计数器是在ios5以后增加的一项内存管理机制,是指内存管理中对引用采取自动...

  • JVM 垃圾回收机制

    Java 语言的一大特点就是可以自动回收垃圾。一下列举了垃圾回收器的算法以及实现原理: 引用计数器算法 引用计数器...

  • ARC模式:自动引用计数器

    ARC模式: 自动引用计数器 实质是在合适的时候自动插入release和autorelease ARC允许重写de...

  • Swift 自动引用计数器(ARC)详解

    Swift使用ARC(自动引用计数器:Automatic Reference Counting)来追踪和管理应用的...

  • OC-堆栈、内存管理

    MRC:手动内存管理 ARC:默认是ARC:automatic Reference Count,自动引用计数器 P...

  • 【code_hyy_基础】ARC?

    基本简介 ARC是Automatic Reference Counting(自动引用计数器)的简称。 ARC是io...

  • ARC基本原理

    基本简介 ARC是Automatic Reference Counting(自动引用计数器)的简称。 ARC是io...

  • ARC

    ARC 1、ARC是Automatic Reference Counting(自动引用计数器)的简称。 ARC是i...

网友评论

      本文标题:swift-自动引用计数器

      本文链接:https://www.haomeiwen.com/subject/jrhuattx.html