Coder Social home page Coder Social logo

swiftplayground's Introduction

Swift中的weak和unowned关键字

1.前言: 循环引用

循环引用是指两个或两个以上对象互相强引用,导致所用对象无法被释放的现象。这是内存泄露的一种情况

有两个类,分别为爸爸(Father)和儿子(Son)。爸爸对儿子强引用,儿子对爸爸强引用。所以,要释放儿子必须先释放爸爸,要释放爸爸,则必须先释放儿子,如此一来,两个对象都无法被释放

在OC中,可以很简单的举出一个循环引用的例子。比如有两个类A和B,A中有一个属性是B类的实例,而B中又有一个属性是A类的实例。同时这两个属性都是strong的,这就导致了一个最简单的循环引用。

实例没有销毁,造成内存泄漏

2.swift中的循环引用

但是由于swift语法的特殊性,这样的例子不像OC中一样容易构造。因为对于一般类型的属性,Swfit要求在一个类的初始化方法中保证它一定有值。这将导致一个死循环。试想一下,A类在初始化的时候要保证它的某一个类型为B的属性先被初始化,而这个属性中又含有一个类型为A的属性需要先被初始化。 这样循环下去的后果是,没有任何一个A或者B类的对象能先被初始化。如果允许代码的话,可以编译,但是运行时会报错:“EXC_BAD_ACCESS”. (简单的理解:当遇到了EXC_BAD_ACCESS异常,意味着访问了一个已经被释放的内存区域。)

但是Swift这个特性并不意味着,在swift里面就不会出现引用循环问题了。因为swift还提供了可选类型,这个类型可以不被赋值,默认值就是nil

与OC类似,解决循环引用问题最简单方法就是把属性定义为weak。

类中循环引用 所以可分为以下3中

2.1. 如果产生循环引用的两个属性都允许为nil,这种情况适合用弱引用来解决 随便哪一个可选类型的属性前面都可以加weak,但记住只要加一个就行了.

class ClassA { weak var classBInstance: ClassB? init(){ //初始化操作 } }

当弱引用所指向的对象被回收后,这个弱引用会自动被置为nil。这一点和OC非常类似。因此也可以看到,由于nil是可选类型的特权,所以weak修饰符仅能修饰可选类型属性。

如果两个类 A 强引用 B B 弱引用A 若B至为nil 则B 不会被deinit 此时打印 B为 nil 但A中的B依然存在 若A至为nil 则A 将被deinit 此时打印 A为 nil 且B中的A也不存在

两个类中,相互引用的两个属性都为可选类型,那么可以在一个属性的前面添加weak关键字,使该变量变为弱引用.

2.2 如果产生循环引用的两个属性一个允许为nil,另一个不允许为nil,这种情况适合用无主引用来解决

只能在不能为nil的那个属性前面加unowned关键字,就是说 unowned设置以后即使它原来引用的内容已经被释放了,它仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil。如果尝试去调用这个引用的方法或者访问成员属性的话,程序就会崩溃.

如下错误 error: Execution was interrupted, reason: signal SIGABRT.

2.3. 如果产生循环引用的两个属性都必须有值,不能为nil,这种情况适合一个类使用无主属性,另一个类使用隐式解析可选类型

隐式解析可选类型: 类似可选类型,默认值可以设置为nil 两个属性一个在类型后面加!设置为隐式解析可选类型,另一个在属性前面加unowned关键字,设置为无主属性.

与OC不同的是,除了弱引用外,swift还提供了无主引用来打破引用循环。根据我们刚刚的讨论,导致循环引用的属性,至少有一个是可选类型。这也就是说,有可能在另一个类里面,它的属性不是可选类型:

class ClassB { unowned var classAInstance: ClassA = ClassA() init(){ //初始化操作 } }

比如在B类中,classAInstance这个属性就可以不是可选类型。在这种情况下,还可以使用无主引用来打破引用循环。语法就是把weak替换为unowned关键字。unowned属性引用的对象被回收后,引用不会被置为nil,也不能被访问,否则会触发运行时错误

闭包

2.4闭包也是引用类型,怎么解决闭包的循环强引用

闭包中对任何其他元素的引用都是会被闭包自动持有的。如果我们在闭包中写了 self 这样的东西的话,那我们其实也就在闭包内持有了当前的对象。这里就出现了一个在实际开发中比较隐蔽的陷阱:如果当前的实例直接或者间接地对这个闭包又有引用的话,就形成了一个 self -> 闭包 -> self 的循环引用

使用 [unowned self] 在闭包中定义一个捕获列表[unowned self],将self变为无主引用.这样就能够在避免产生循环强引用了

lazy var group:() -> String = { // 相当于一个没有参数返回string的函数 [unowned self] in // 定义捕获列表,将self变为无主引用 if let text = self.text { // 解包 return "(self.name), (text)" }else { return "(self.name)" } }

swiftplayground's People

Contributors

imkiller avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.