티스토리 뷰

Auto Reference Counting - Part 2

( a.k.a ARC )



참고 자료

Swift 4.2 - The Swift Programming Language (Apple Inc.)





4) 클래스 인스턴스들 사이의 강한 순환 참조

    (Strong Reference Cycles Between Class Instances)




In the examples above, ARC is able to track the number of references to the new Person instance you create and to deallocate that Person instance when it’s no longer needed.


(1) 편에서 본 것과 같이, ARC 는 여러분이 만든 새 Person 인스턴스에 대한 참조의 수를 추적할 수 있고, 그것이 더 이상 필요하지 않을 때 Person 인스턴스를 할당 해제할 수 있다. 



However, it’s possible to write code in which an instance of a class never gets to a point where it has zero strong references. This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a strong reference cycle.

 

그러나, 클래스의 인스턴스가 강한 참조가 없는 지점에 결코 도달하지 못하는 코드가 작성될 가능성이 있습니다 . 이는 만약 두 클래스의 인스턴스가 서로를 강하게 붙잡고 있는 경우에 발생할 수 있고, 이러한 이유로 각각의 인스턴스는 서로를 활성화(참조)하는데, 이것이 바로 강한 순환 참조라 알려져 있는 개념입니다.



You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. This process is described in Resolving Strong Reference Cycles Between Class Instances. However, before you learn how to resolve a strong reference cycle, it’s useful to understand how such a cycle is caused.


여러분은 Strong 참조 키워드(기본값)를 사용하는 대신,  weak 또는 unowned 참조 키워드를 가진 클래스들 사이에서 관계의 일부를 정의함으로서 강한 순환 참조를 해결할 수 있습니다. 이 과정은 아래의 Resolving Strong Reference Cycles Between Class Instances 에 자세히 설명되어 있습니다. 그러나, 강한 순환 참조를 해결하는 방법을 배우기 전에, 어떻게 이러한 순환이 발생하는지 이해하는 것은 유용할 겁니다.



Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person and Apartment, which model a block of apartments and its residents:


다음은 어떻게 우연에 의해 강한 순환 참조가 만들어질 수 있는지에 대한 예시입니다. 이 예는 Person 그리고 Apartment 라 불리는 두 개의 클래스를 정의하고 있습니다. 하나의 아파트 단지와 단지의 거주자들의 모형을 만들어 뒀다는 정도로 생각해보죠.



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

}



Every Person instance has a name property of type Stringand an optional apartment property that is initially nil. The apartment property is optional, because a person may not always have an apartment.


모든 Person 클래스의 인스턴스는 String(문자열) 타입name 프로퍼티 하나를 가지고 있습니다 그리고 nil 로 초기화 되는 옵셔널 타입의 apartment 프로퍼티를 가지고 있습니다. apartment 프로퍼티는 옵셔널인데, 왜 그럴까요? 사람은 항상 아파트를 가지고 있지 않기 때문이죠. 있을 수도 있고 혹은 없고.



Similarly, every Apartment instance has a unit property of type String and has an optional tenant property that is initially nil. The tenant property is optional because an apartment may not always have a tenant.


비슷하게, 모든 Apartment 클래스의 인스턴스는 String 타입의 unit 프로퍼티를 가지고 있으며 마찬가지로 nil 로 초기화되는 옵셔널 타입의 tenant 프로퍼티를 가지고 있습니다. tenant 프로퍼티도 옵셔널인데, 아파트라고 해서 항상 세입자가 들어와 있는건 아니잖아요. 그래서 없을 수 있으니까 옵셔널로 선언했어요.  



Both of these classes also define a deinitializer, which prints the fact that an instance of that class is being deinitialized. This enables you to see whether instances of Person and Apartment are being deallocated as expected.


또한 이 클래스 둘 다 내부에 deinitializer(디이니셜라이저, 클래스의 인스턴스가 메모리에서 해제될 때 자동으로 작동하는 부분)를 정의하고 있는데, 클래스의 인스턴스가 초기화 해제 되고 있음에 대한 사실을 프린트 해주는 부분이죠. 이것은 여러분에게 Person 클래스의 인스턴스든 Apartment 클래스의 인스턴스든 예상대로 할당 해제 되고 있음을 보여주게 할 수 있어요.



This next code snippet defines two variables of optional type called john and unit4A, which will be set to a specific Apartment and Person instance below. Both of these variables have an initial value of nil, by virtue of being optional:


다음의 코드 스니펫(오려낸 부분)은 'john' 그리고 'unit4A' 라 불리는 두 개의 옵셔널 타입을 가진 변수를 정의하고 있어요. 아래에서 이 두 개의 변수에는 특정 Apartment 그리고 특정 Person 의 인스턴스가 설정될 것입니다(왜 여기서 '특정'이란 말이 들어갔을까요? 왜냐하면 클래스는 참조타입이 때문에 인스턴스를 생성할때마다 메모리 상에서 독립된 공간을 갖기 때문이에요. 같은 Person 타입이어도, 변수에 할당할 때는 서로 다른 메모리 주소를 참조하고 있는 것이죠). 이 두 개의 변수는 옵셔널이기 때문에 초기 값으로 nil 을 가지고 있어요 :  



var john: Person?

var unit4A: Apartment?



You can now create a specific Person instance and Apartment instance and assign these new instances to the john and unit4A variables:


여러분은 이제 특정 Person 클래스의 인스턴스와 Apartment 클래스의 인스턴스를 만들어 낼 수 있어요, 그리고 아래는 이러한 새 인스턴스들을 john 과 unit4a 변수들에 할당 할 수 있음을 보여주고 있어요:



john = Person(name: "John Appleseed")

unit4A = Apartment(unit: "4A")



Here’s how the strong references look after creating and assigning these two instances. The john variable now has a strong reference to the new Person instance, and the unit4A variable has a strong reference to the new Apartment instance:


다음은 이 두 개의 인스턴스를 생성, 할당한 후에 강한 참조가 어떻게 보이는지 그림을 통해 보여주고 있습니다. john 변수는 이제 새 Person 클래스의 인스턴스에 강한 참조를 가지게 되었고, unit4A 변수는 새 Apartment 클래스의 인스턴스에 대해 강한 참조를 가지게 되었습니다. 





You can now link the two instances together so that the person has an apartment, and the apartment has a tenant. Note that an exclamation mark (!) is used to unwrap and access the instances stored inside the john and unit4A optional variables, so that the properties of those instances can be set:


여러분은 이제 두 인스턴스를 둘 다 연결하여, 사람(the person)은 아파트를 가지고, 아파트(the apartment)는 세입자를 가질 수 있게 되었습니다, 감탄을 나타내는 기호인 느낌표(!) 는 첫 째로 언래핑(옵셔널을 벗겨내는 것)을 위해서 사용되는 것과 둘 째로  john 과 unit4A 옵셔널 변수들 내부에 저장된 인스턴스에 접근하기 위해 사용된다는 것에 주목하세요. 이러한 인스턴스들의 프로퍼티들이 설정될 수 있게 하기 위함이죠.



john!.apartment = unit4A

unit4A!.tenant = john



Here’s how the strong references look after you link the two instances together:


다음의 사진을 통해 여러분이 두 개의 인스턴스를 함께 연결한 후, 강한 참조가 어떻게 나타나는지 확인할 수 있습니다. 





Unfortunately, linking these two instances creates a strong reference cycle between them. The Person instance now has a strong reference to the Apartment instance, and the Apartment instance has a strong reference to the Person instance. Therefore, when you break the strong references held by the john and unit4A variables, the reference counts do not drop to zero, and the instances are not deallocated by ARC:


불행하게도, 이 두 개의 인스턴스들을 연결하는 것은 이 인스턴스들 사이에서 강한 순환 참조를 만들어냅니다. Person 인스턴스는 이제 Apartment 인스턴스에 대해 강한 참조를 가지고 Apartment 인스턴스는 Person 인스턴스에 대해 강한 참조를 가지게 되죠. 그러므로, 여러분이 john, unit4A 변수들에 의해 잡혀있는 강한 참조들을 풀어줄 때(아래 사진처럼 nil 을 할당), 참조 카운트는 0으로 떨어지지 않고 인스턴스는 ARC 에 의해서 할당 해제되지 않습니다. :



john = nil

unit4A = nil



Note that neither deinitializer was called when you set these two variables to nil. The strong reference cycle prevents the Person and Apartment instances from ever being deallocated, causing a memory leak in your app.


여러분이 이 두 개의 변수에 nil 을 부여했을 때, 어떤 디이니셜라이저도 호출되지 않는다는 점에 주목하세요. 강한 순환 참조는 Person 과 Apartment 인스턴스가 할당이 해제되는 것을 방지하여, 앱에서 메모리 누수(memory leak)를 유발합니다. 



Here’s how the strong references look after you set the john and unit4A variables to nil:


다음에서 john 과 unit4A 변수에 nil 을 부여한 후에 강한 참조가 어떻게 보여지는 확인해보세요 :)




The strong references between the Person instance and the Apartment instance remain and cannot be broken.


Person 인스턴스와 Apartment 인스턴스 사이의 강한 참조는 남아있게 되고 메모리에서 해제될 수 없게 됩니다








번역의 오역에 대한 지적 감사드리겠습니다 !

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함