Swift 弱引用和无主引用之间有什么区别

Swift 弱引用和无主引用之间有什么区别

了解iOS的内存管理对iOS和macOS的开发至关重要。弱引用和非自有引用的概念是很难理解的,特别是对于初学者来说。ARC(自动引用计数)可能已经为我们解决了很多问题。Swift仍然需要你在很多时候管理引用,当你不处理价值类型的时候。

ARC或自动引用计数

自动引用计数(ARC)是用来跟踪和管理应用程序的内存使用的。在大多数情况下,这意味着内存管理在Swift中 “只是工作”,你不需要自己考虑内存管理。当类实例不再需要时,ARC会自动释放这些实例使用的内存。

注意,在Swift中,默认情况下,引用被算作强。

import UIKit
class ProductListController: UIViewController {

   // Create a strong reference to a ProductListDataSource() instance. When the ProductListController instance is deallocated, it will decrease the reference count of the ProductListDataSource instance by 1.
   let dataSource = ProductListDataSource()

   override func viewDidLoad() {
      super.viewDidLoad()
   }
}

在上面的例子中,ProductListController类有一个ProductListDataSource()类型的强引用。

当一个对象的强引用被分配到该对象时,该对象的引用计数会增加1。当一个对象的强引用被删除时,该对象的引用计数将减少1。

拥有强引用是什么意思?

让我们先来了解一下什么是强引用。它本质上是一个默认的引用(指针和所有),但它本身很特别,因为它通过增加ARC的保留计数来保护被引用的对象不被删除。从本质上讲,只要有一个对象的强引用,它就不会被取消分配。这一点在以后我解释保留周期之类的东西时要记住。

Swift代码库几乎只使用了强引用。所有的属性声明默认都是强引用。一般来说,当对象的层次关系是线性的,使用强引用是允许的。当它们的层次关系从父到子时,依靠强引用通常是明智的。

UIView.animate(withDuration: 0.5) {
   self.view.alpha = 0.5
}

由于animateWithDuration是UIView上的一个静态方法,这里的闭包是父类,自我是子类。

弱引用

弱引用是解决Swift中保留循环问题的方法之一。请注意,弱引用不会增加或减少一个对象的引用计数。即使ARC的引用计数大于1,它们也可以被拆解。

基本上,我们在Swift中使用弱引用关键字来标记一个引用为弱引用。另外,弱引用不能用let关键字来声明,因为它在某些时候会被传递给nil。这是因为当弱引用指向对象时,该对象可能会被取消分配。在你认为可能产生保留循环的代码中应该有一个弱引用。

如何使用弱引用来解决保留循环问题

我们将看到一个关于如何修复保留循环的例子。我们将创建一个数据源模型类,使用网络请求获取初始数据。

import UIKit
class ProductListDataSource {

   func loadInitialData(_ completion: ((_ isSuccess: Bool) -> ())?) {
      // assume perform networking request to fetch initial data
      // returning completion handler after finishing the task
      completion?(true)
   }
}
class ProductListController: UIViewController {

   // Created a strong reference to a ProductListDataSource() instance. When the ProductListController instance is deallocated, it will decrease the reference count of the ProductListDataSource instance by 1.
   let dataSource = ProductListDataSource()

   override func viewDidLoad() {
      super.viewDidLoad()

      /*
      1. Calling the loadInitialData function no longer creates a retain cycle.
      2. Self (ProductListController) has a strong reference to the data source.
      3. Completion handler has a weak reference to self (ProductListController).
      */
      dataSource.loadInitialData { [weak self] isSuccess in
         guard let self = self else { return }

         // perform tasks that need to be done after successfully fetching data
      }
   }
}

在上面的例子中,你可以看到我们使用了self的弱引用(ProductListController()),因为一旦从服务器获取数据,可能需要执行某些操作。

Swift中的无主引用

无主引用与弱引用非常相似,但有一点不同。无主引用会给你一个保证,当变量被访问时,它不会为零。

与弱引用类似,无主引用不会增加或减少一个对象的引用计数。我们可以说这是另一种解决保留循环的方法。当引用所指向的实例为nil时,访问一个无主引用将导致一个致命的程序错误。

两者之间有什么区别?

弱引用是一种不会阻止被引用对象被Swift运行时去分配的引用。

另一方面,无主引用是一种不对被引用对象保持强势控制的引用。然而,与弱引用不同,无主引用被认为总是有一个值。

总结一下两者之间的区别 --

弱引用和无主引用之间的区别

弱引用 无主引用
它可以被声明为可选的。 它不能被声明为可选的。
它可以在任何时候变成nil。 它在任何时候都不能成为nil。
它防止对象被取消分配。 它不会阻止对象被取消分配。
如果访问去分配的引用对象,发生运行时错误的机会较少。 如果访问去分配的引用对象,发生运行时错误的可能性很大。

使用哪种引用是合适的?

使用弱引用

当两个对象之间存在一种关系,其中一个对象不应该对另一个对象有很强的控制力,你应该利用弱引用来阻止保留循环。当两个对象相互强烈引用时,就会产生一个保留循环,禁止Swift运行时对任何一个对象进行解配。

例如,在两个对象之间建立父子关系时,你通常会使用弱引用来作为孩子对父对象的引用,以避免父对象被孩子永久地维护。

使用未拥有的引用

当两个对象之间存在一种关系,其中一个对象对另一个对象没有强大的控制力,但你确信被引用的对象将在引用对象的生命周期内一直存在,你应该使用一个非自有引用。

例如,如果视图控制器不断地展示同一个视图,你可以为视图控制器对视图的引用使用非自有引用,因为只要视图控制器存在,该视图就会一直存在。

结论

总之,这两种引用在各自的情况下都发挥着重要作用。但大多数时候,我们在应用中使用弱引用。这是因为弱引用在内存管理的情况下更好。由于弱引用可以被声明为可选的,并且可以处理nil,所以我们建议使用它们。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

Swift 教程