Weak vs Unowned

Minseok, Kim·2021년 7월 4일
0

요약

weak(optional) vs unowned(non-optional)

개념

weakunowned는 Strong Reference Cycle을 해결하기 위해서 사용한다.
두 방식의 차이는 optional과 non-optional의 차이이다.

weak의 경우에는 optional을 사용해야한다. unonwed는 값이 무조건 있다고 가정하고 사용하기 때문에 optional을 채택해서는 안된다.

다음은 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) 두개의 class가 서로를 property로 가리키고 있는 상태에서, Car을 해제한 후 Company의 property car을 출력해보니 nil이 출력되는 것을 볼 수 있다.

weak는 기본적으로 가리키던 instance가 메모리에서 해제될 경우 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

위와 같이 Error을 띄우게 된다. weak와 달리 unowned는 가리키던 instance가 해제되면 nil을 반환하지 않는다. 대신 해제된 메모리 주소값을 계속해서 들고 있는다. 따라서 이에 접근하려 할 경우, 다음과 같이 Error을 뿜어낸는 것이다.

이러한 이유로 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

profile
iOS, Swift Dev

0개의 댓글