swift防止循环引用简单整理
weak
弱引用不会对其引用的实例保持强引用,因而不会阻止 ARC 销毁被引用的实例。这个特性阻止了引用变为循环强引用。ARC 会在引用的实例被销毁后自动将其赋值为nil。并且因为弱引用可以允许它们的值在运行时被赋值为nil,所以它们会被定义为可选类型变量,而不是常量。
unowned
和弱引用类似,无主引用不会牢牢保持住引用的实例。和弱引用不同的是,无主引用在其他实例有相同或者更长的生命周期时使用。无主引用通常都被期望拥有值。不过 ARC 无法在实例被销毁后将无主引用设为nil,因为非可选类型的变量不允许被赋值为nil。
代理的循环引用
使用weak标记
如下定义两个协议
protocol TestProtocol: class {
func testProtocolFunc()
}
@objc protocol TestProtocol2 {
func testProtocolFunc2()
}
⚠️注意:在使用weak标记时delegate时,协议需要继承class或用@objc标记,否则会爆错。'weak' may only be applied to class and class-bound protocol types, not 'TestProtocol'
使用协议时:
class TestClass {
weak var delegate: TestProtocol?
weak var delegate2: TestProtocol2?
func test() {
self.delegate?.testProtocolFunc()
self.delegate2?.testProtocolFunc2()
}
}
闭包的防止循环引用
闭包防止循环引用时使用weak unowned的原则:
a、在闭包和捕获的实例总是互相引用并且总是同时销毁时,将闭包内的捕获定义为无主引用。
b、相反的,在被捕获的引用可能会变为nil时,将闭包内的捕获定义为弱引用。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为nil。这使我们可以在闭包体内检查它们是否存在。
c、如果被捕获的引用绝对不会变为nil,应该用无主引用,而不是弱引用。
如(a、b暂未遇到合适的例子):
class SwiftViewController: UIViewController {
var swiftBlock: ((String) -> Void)?
var name = ""
override func viewDidLoad() {
super.viewDidLoad()
self.swiftBlock = { [unowned self] str in
print("\(self.title ?? "没有标题")")
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let block = self.swiftBlock {
block("测试swiftblock")
}
}
deinit {
print("SwiftViewController销毁了")
}
}
类的循环引用
使用weak例,定义了两个类:Person和Apartment,用来建模公寓和它其中的居民。Apartment的tenant属性被声明为弱引用以防止循环引用。
class Person {
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: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
建立两个变量(john和unit4A)之间的强引用,并关联两个实例
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
使用unowned例,定义了两个类,Customer和CreditCard,模拟了银行客户和客户的信用卡。这两个类中,每一个都将另外一个类的实例作为自身的属性。这种关系可能会造成循环强引用。一个客户可能有或者没有信用卡,但是一张信用卡总是关联着一个客户,因此将customer属性定义为无主引用,用以避免循环强引用。
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
建立两个变量(john和card)之间的强引用,并关联两个实例
var john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
(如有错误欢迎斧正)
参考:
极客学院自动引用计数
swift中的delegate