---
# System prepended metadata

title: ARC
tags: [복 & 면]

---

# ARC 
- Swift 는 자동 참조 카운팅(ARC)을 사용하여 앱의 메모리 사용량을 추적하고 관리합니다.
    - 자동으로 메모리를 관리해주는 방식입니다.
    - 개발자가 메모리 관리에 신경을 덜 쓸 수있게 편리하게 해준다.
    - 더이상 필요하지 않는 클래스의 인스턴를 메모리에서 해제하는 방식으로 동작합니다.


### ARC 어떻게 동작해요?
- 새로운 `class`인스턴스 생성할때마다, ARC는 해당 인스턴스의 정보를 적재하기 위해 메모리의 `chunk`를 할당한다.
- 이 메모리는 인스턴스 타입에 대한 정보를 해당 인스턴스와 관련되어 저장된 프로퍼티들의 값을 함께 포함 하여 유지합니다.
- 인스턴스가 더이상 필요하지 않게 될때, ARC는 해당 인스턴스에 의해 사용되는 메모리를 해제하고 해제된 해당 메모리는 다른 목적을 위해 사용될 수 있습니다.


### 클래스 인스턴스 간의 강력한 참조 순환
```swift
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") }
}
```
![image](https://hackmd.io/_uploads/rJQDToNL6.png)


- 먼저 두 클래스가 서로 강한 참조를 하고 있어, 순환참조가 발생합니다.
- 서로 인스턴스를 강하게 참조하여 서로 해제되지 않는 순환 참조이다.
- 이러한 방법을 해결하기 위해서는 약한 참조, 미소유 참조를 사용해야한다!

##### 약한 참조란?
- 강한 참조을 방지하기 위해서 사용한다.
- 약한 참조는 속성 또는 변수 선언에 있어 `weak` 키워드를 배치하여 나타냅니다.
- 약한 참조는 참조하는 인스턴스를 강력하게 유지하지 않기 때문에,
    - 따라서 ARC는 참조하는 인스턴스가 할당 취소될 때 약한 참조를 nil로 자동으로 설정됩니다. 
    - 또한 약한 참조는 런타임에 값을 nil로 변경할 수 있도록 허용해야 하기 때문에 항상 선택적 형식의 상수가 아닌 변수로 선언됩니다.


```swift
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") }
}

var john: Person?
var unit4A: Apartment?


john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")


john!.apartment = unit4A
unit4A!.tenant = john
```
이제는 `weak var` 인 약한참조가 생겼다!
![image](https://hackmd.io/_uploads/rJzKpsEU6.png)

Person에서는 여전히 apartment인스턴스에 강한참조가 있지만 apartment인스턴스에서는 이제 약한 참조가 있습니다. Person 즉, 변수를 nil로 설정하여 john변수가 보유하는 강력한 참조를 해제하면 Person인스턴에 대한 강력한 참조가 더 이상 없습니다.

```swift
john = nil
```
인스턴스에 person 더이상 없기 때문에 할당 취소 tenant-> nil이다.
Apartment 인스턴스에 대해 유일하게 남아 있는 강력한 참조는 unit4A 변수에서 가져온 것입니다. 강력한 참조를 깨면 Apartment 인스턴스에 대한 강력한 참조가 더 이상 없습니다.

```swift
unit4A = nil
```
Apartment에 대한 강한 참조가 없기때문에 할당이 취소됩니다.

![image](https://hackmd.io/_uploads/BkMcRsEI6.png)


### 소유되지 않은 참조
- 약한 참조와 같이 소유되지 않는 참조는 참조하는 인스턴스를 강력하게 유지하지 않습니다. 그러나 약한 참조와 달리 소유하지 않는 참조는 다른 인스턴스의 수명이 같거나 더 긴 경우에 사용 됩니다.
    - 같은말?일수도? 미소유 참조는 강한 참조를 방지하면서도, 참조하는 인스턴스가 항상 존재할 것이라는 가정 하에 사용된다.
    - `unowend`키워드를 사용하여 나타냅니다.

```swift
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") }
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
```
- customer 인스턴스(john)가 생성되고, creditCard 인스턴스를 참조합니다.
- john이 nil로 설정되면 Customer 인스턴스는 해제되지만, creditCard인스턴스는 Customer의 생명주기에 영향을 받지 않아 계속 존재합니다.

- 미소유 참조 특징
    - 미소유 참조는 참조하는 인스턴스의 생명 주기에 영향을 주지 않습니다.
    - 참조하는 인스턴스가 해제되면, 미소유는 참조는 여전히 그 값을 유지함

#### 클로저에 대한 강한 참조 주기

```swift
class HTMLElement {
    let name: String
    let text: String?
    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }
    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}
```
- asHTML 클로저가 self를 캡쳐하여 강한 참조가 발생합니다.
![image](https://hackmd.io/_uploads/rJ5o82VLT.png)

- 캡쳐리스트를 사용하여 강한 참조를 방지합니다.
    - [weak self], [unowned self] 이렇게 사용하여 강한 참조 방지, 클로저가 인스턴스를 강하게 참조하는지 않아 순환 참조가 발생하지 않는다.

```swift
 lazy var asHTML: () -> String = { [unowned self] in
     냉무
    }
```
