
메모리 공간에 데이터를 할당하는 방법은 크게 두가지로 나뉜다. Value Type과 Reference Type이다. value type은 스택 공간에, 레퍼런스 타입은 힙 공간에 데이터를 할당한다. Value Type의 경우 필요시에 항상 메모리의 값이 복사되어 전달되며 블록을 닫는 괄호를 만나면 메모리에서 자동 제거 된다. 레퍼런스 타입은 메모리의 주소를 전달해 프로그래머가 원하는 시점에 동적으로 메모리를 가지고 놀아야한다. Swift의 경우 레퍼런스 타입의 메모리 관리를 ARC 모델을 통해 사용한다. 이를 이용하는 대표적인 타입은 클래스와 클로저이다. 해당 타입을 다 사용했는데 할당이 해제되지 않으면 메모리 누수 현상이 발생한다.
ARC는 Automatic Reference Counting으로, 해당 인스턴스를 참조하는 인스턴스들의 수를 Counting해뒀다가 0이 되면 자동으로 메모리 해제를 해주는 방식을 이야기 한다.
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
Person 클래스 예제이다.
reference1 = Person(name: "John Appleseed")
이렇게 되면 이름이 John인 Person class의 Referencing Count가 1로 증가한다.
reference2 = reference1
reference3 = reference1
위의 코드를 거치면 Reference Count가 3으로 증가한다.
reference1 = nil
reference2 = nil
이런 상태에서는 이름이 John인 Person 인스턴스가 해제될까?
답은 X 이다.
reference3이 여전히 이름이 John인 Person 인스턴스를 가리키고 있기때문에 여전히 할당되어있는 상태이다.
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 }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
Person의 apartment가 Apartment class를 가리키고, Apartment의 tenant가 Person class를 가리킨다.
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

객체를 생성하고 할당해줌을 통해 Strong 레퍼런스가 2개가 생겼다.
john!.apartment = unit4A
unit4A!.tenant = john

이렇게 서로가 서로를 가리킴으로써 각각의 인스턴스는 Reference Count가 2가 되고, Strong Reference Cycle이 생기게된다. 불행히도 이렇게 생성된 인스턴스는 할당된 메모리가 자동으로 회수되지 않는다.
john = nil
unit4A = nil
이렇게 처리해줘도 각각의 인스턴스에 대한 Reference Count가 1이기 때문이다.
이러한 현상이 바로 메모리 누수이다. 메모리 해제가 되지 않고 해제시킬 방법이 없다.
위의 두 레퍼런스는 인스턴스의 Reference Count에 포함되지 않는다. weak 레퍼런스는 참조하던 것이 메모리에서 할당 해제되었을때 nil로 확인이 가능하나 unowned 레퍼런스는 확인이 불가능하고 에러가 발생한다. 그럼에도 불구하고 unowned 레퍼런스를 사용하는 이유는 속도가 살짝 빠르다고 한다.
unowned 레퍼런스는 할당이 해제되지 않은 인스턴스를 참조하는것이 정말 정말 확실하고 보장될때만 사용해야한다. 이런 이유로 weak 레퍼런스를 많이 사용한다.
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") }
}
weak의 경우, 위의 예시와 같이 사용한다. 이때 weak 레퍼런스는 let으로 만들 수 없음을 주의해야한다.

unowned는 Customer가 없어지면 Credit Card의 효력 또한 없어지기 때문에 이렇게 종속적인 형태일 때 주로 사용한다.
unowned 레퍼런스는 optional 값을 명시적으로 언래핑 하지 않고 사용할 수 있다.
ARC는 Automatic Reference Counting으로, 해당 인스턴스를 참조하는 인스턴스들의 수를 Counting해뒀다가 0이 되면 자동으로 메모리 해제를 해주는 방식을 이야기 한다. 메모리에 대해 개발자가 생각할 필요가 없으나, 몇몇 경우에 strong reference cycle이 발생하므로 이를 유의해서 써야한다. 이를 해결하기 위한 방법으로 weak과 unowned 키워드를 이용할 수 있다.