본문 바로가기
Swift Deeep Dive

[Swift] ARC에 관한 문제 해결하기(클로저에 관하여)

by shinhyogeun 2020. 7. 25.

저번 시간에는 클래스를 참조하면서 발생할 수 있는 ARC와 관련된 문제점을 알아보고 약한 참조와 미소유 참조 등 다양한 해결책도 같이 알아보았다. 이번 시간에는 ARC에 관한 마지막 글로 이런 강한 참조 문제가 클로저 내부에서도 발생될 수도 있고 이러한 것을 해결하는 해결책도 같이 알아보려고 한다.(참조가 가능한 것은 클로저와 클래스가 있다.)

 

1. 문제 발생 원인

다음을 보면 HTMLElement라는 클래스 내부에 지연 저장 프로퍼티인 asHTML이 보인다. 그리고 그속에서 self.text와 slef.name 등이 사용되고 있는 것들도 보인다. 이것은 HTMLElement라는 클래스 내부의 하나의 프로퍼티인 asHTML 클로저내에서 자신이 속해 있는 클래스를 다시 참조하는 것이다.

그래서 우리가 만약 다음과 같은 코드를 실행한다면 heading이라는 상수를 클래스를 참조하게 하고 또한 text 프로퍼티 값이 없으므로 그경우의 asHTML 클로저를 조금 개선하고 있다. 여기서 중요한 것은 우리머리 속에 참조횟수를 계속 파악해야 한다. 지금은 정확하게 

 

HTMLElement 클래스는 2번(1번은 heading상수가 그리고 1번은 클로저 내부에서) 그리고 그 안의 클로저는 한번 참조 되고 있는 것(by 지연저장 프로퍼티에 의해!!)을 알아야한다. 다음의 그림을 참고하자.

자 그러면 여기서 문제가 생기는 것도 당연히 느껴질 것이다.(느껴져야 한다..ㅠㅠ) 여기서 변수들 이름은 위의 코드와 다르지만 

원리면에서 보면  paragraph에 nil을 할당하면 강한참조 순환이 발생한다. 

 

2. 획득목록을 통한 해결 

 

획득목록을 통한 해결은 생각보다 간단하다. 정해진 양식에 맞춰서 작성하면 우리는 클로저 내부에서 일어나는 참조를 약한참조 또는 미소유 참조로 쉽게 바꿀 수 있다. 양식은 다음과 같다.

 

var apple : () -> String =  { [weak self] in 

   ....

}

이렇게 작성하면 ....에서 참조하는 self는 모두 약한 참조를 하게 되고 그렇게 함으로서 메모리 누수를 막을 수 있다.

(nil을 부여했을 때의 메모리 해제 계산과정은 생략한다.)

 

var apple : () -> String = { [unowned self] in

  ....

}

이것은 미소유 참조 양식이다.  이것 또한 메모리 누수를 막을 수 있지만 메모리에서 해제된 후 절대 부르면 안되는 양식이다.

(그 이유는 unowned에는 nil값이 들어 갈 수 없기 때문이다. 따라서 다른 곳에서도 같은 클로저를 부를 수 있다면 weak을 쓰는 것을 추천한다. )

 

 

지금까지 3글에 걸쳐서 ARC에 관해서 알아보고 생길 수 있는 문제점과 해결방안을 알아보았다.

ARC는 제법 어려운 개념으로 이것을 잘 활용한다면 효율적인 메모리 관리를 할 수 있다.