Weak vs Unowned


サマリ

weak (optional) vs unowned (non-optional)

コンセプト

weakおよびunownedは、Strong Reference Cycleを解決するために使用される.
2つの方法の違いは、オプションと非オプションの違いです.weakの場合、オプションを使用する必要があります.unonwed仮定値は無条件で使用され、オプションは使用されない.weakを使用したコードを次に示します.
class Company {
    let name: String
    weak var car: Car?
    
    init(name: String) {
        self.name = name
        print("Company Init")
    }
    
    deinit { print("Company Deinit") }
}

class Car {
    let name: String
    var company: Company?
    
    init(name: String) {
        self.name = name
        print("Car Init")
    }
    deinit { print("Car Deinit") }
}


var k8: Car? = .init(name: "k8")	// Car Init
var kia: Company? = .init(name: "KIA")	// Company Init

k8?.company = kia
kia?.car = k8

k8 = nil	// Car Deinit
kia?.car	// nil
Company(kia)Car(k8)の2つのクラスが互いに相手を指し合う場合、Carを解除した後にCompanyを出力する属性carは、出力nilを見ることができる.weakデフォルトでは、インスタンスがメモリから解放されると、nilが割り当てられます.したがって、Company(kia)のproperty carが指すCar(k8)が解除されると、carがnilに割り当てられる.
では、上記のコードでweakunownedに変更したらどうなるのでしょうか.
class Company {
    let name: String
    unowned var car: Car?
    
    init(name: String) {
        self.name = name
        print("Company Init")
    }
    
    deinit { print("Company Deinit") }
}

class Car {
    let name: String
    var company: Company?
    
    init(name: String) {
        self.name = name
        print("Car Init")
    }
    deinit { print("Car Deinit") }
}


var k8: Car? = .init(name: "k8")	// Car Init
var kia: Company? = .init(name: "KIA")	// Company Init

k8?.company = kia
kia?.car = k8

k8 = nil	// Car Deinit
kia?.car	//Error

上の図に示すように、エラーが表示されます.weakとは異なり、unownedが示すインスタンスが解除されるとnilは返されません.代わりに、無効なメモリアドレス値の取得を続行します.そのため、接近しようとすると、次のエラーが発生します.
したがって、unownedはnon-optionalに設定する必要があります.次のコードは、unownedが正しく使用されているコードです.
class Company {
    let name: String
    unowned let car: Car
    
    init(name: String, car: Car) {
        self.name = name
        self.car = car
        print("Company Init")
    }
    
    deinit { print("Company Deinit") }
}

class Car {
    let name: String
    var company: Company?
    
    init(name: String) {
        self.name = name
        print("Car Init")
    }
    deinit { print("Car Deinit") }
}

参考資料


https://babbab2.tistory.com/27
http://minsone.github.io/mac/ios/rules-of-weak-and-unowned-in-swift
https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html