swift防止循环引用简单整理

2017-10-23  本文已影响107人  悃破

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

上一篇 下一篇

猜你喜欢

热点阅读