ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ARC란
    Swift 2021. 4. 21. 16:15

    ARC : Automatic Reference Counting

    Swift의 메모리 관리 모델 입니다.

    stack에 저장된건 메모리 관리가 필요없지만, heap에 있는건 직접 제거가 필요하죠 하지만 RC 로 자동 관리하는게 바로 ARC 입니다.

     

    zeddios.tistory.com/1213

     

    Swift ) ARC / Strong Reference Cycle 해결 방법(weak, unowned)

    안녕하세요 Zedd입니다. 그냥 갑자기 이런 의문이 들었어요. Strong Reference Cycle을 해결하는 방법이 weak와 unowned를 사용하는거잖아..weak는 진짜 많이 쓰는데 unowned는 진짜 한번도 안써본듯... unowned를

    zeddios.tistory.com

    위의 글로 아주 많은 도움이 되었습니다. 감사합니다.

     

    기본 이해

    ARC를 이해하기 위해서는 소유정책과 참조카운트에 대해서 이해가 필요하다.

    소유자 수를 저장하는걸 참조카운트라고 한다.

    소유자가 retain 메소드를 호출해서 소유권을 얻으면 참조카운트가 +1이 되고, release 메소드를 호출해서 소유권을 포기하면 참조카운트가 -1이 된다.

    해당 instance는 참조카운트가 0이면 메모리에서 자동 제거되는게 포인트..!

     

    1. ARC란 무엇인가?

     

    : Automatic Reference Counting 

    자동 레퍼런스 카운팅, 즉 자동으로 메모리를 관리해준다는 뜻입니다. 참조 카운팅이 0이되면 알아서 메모리에서 해제되는 방식입니다.

    - 컴파일 타임에 작동

    컴파일 타임이란? https://kkimin.tistory.com/28

     

    2. ARC의 단점은 무엇일까요?

     

    : retain Cycle이 발생할 수 있다는 점 입니다. 

     

    3. retain Cycle이란?

     

    : 순환 참조 서로가 서로를 소유하게되면 메모리에서 해제되지 않는 경우를 말합니다. 흔히 delegate 패턴에서 weak으로 선언하지 않았을때 부모뷰를 소유하고 있는 자식뷰가 있고, 부모뷰가 pop되었을때 메모리에서 부모뷰가 해제 되어야 하지만, 참조 카운팅이 1이기때문에 해제되지 않는 현상을 예로 들 수 있습니다.

     

    code로 살짝 봐보자 아래가 바로 ViewController를 지우면 ViewModel이 지워질거라 착각하는 예제다.

    protocol TestDelegate: class {
    }
    
    class ViewModel {
    	var delegate: TestDelegate? // 여기를 weak으로 선언해야함
        
    	deinit {
    		print("deinit")
    	}
    }
    
    class ViewController: TestDelegate {
    	let model = ViewModel()
        model.delegate = self
        
        deinit {
        	print("deinit?")
        }
    }

    그런데 또 없을까? delegate 패턴은 너무 평범하니까

    Closure가 self를 캡쳐했을때지....! (closure가 self를 강하게 참조 하면서 클로져 실행이 끝나기 전까지 self는 메모리에서 해제되지 않는거야. 즉, 인스턴스를 해제한다고 해도 해제되지 않는 문제)

    그래서 내가 많이 사용하는 방법이 아래와 같음 (Closure Captuer List)

    something.do(completion : { [weak self] result in
    	guard let `self` = self else { return }
    })

    (그런데 항상 클로져속 self는 retain cycle을 발생시킬까? : 정답은 아님 : https://kkimin.tistory.com/35

     

    하나 더 NSTimer 보통 target , selector 넘겨줄때 self 로 지정할텐데 이때도 Invalidate 호출 안하면 메모리 릭이 발생한다.

     

    4. weak과 Strong은 무엇일까요? / unowned은?

     

    strong은 객체를 소유하여 레퍼런스 카운트를 증가하는 property입니다. (값 지정 시점에 retain되고, 참조가 종료될때 release 됩니다.)

    weak은 객체를 소유하지 않고, 주소값만 가지고 있는 개념입니다. 자신이 참조는 하지만 메모리를 해제할 수 있는 권한은 다른 클래스에있습니다. 메모리가 해제될 경우 자동으로 레퍼런스가 nil이 되기 때문에 항상 옵셔널이어야합니다.

    즉 대상이 사라지면 자동으로 초기화 해준다는것이죠...! 

    unowned은 자신이 참조하는 인스턴스의 retain count를 증가시키지 않습니다. nil이 될 수 없어 옵셔널로 선언되어선 안되고(이제 아님, 아래 참고), 사라지지않을것이라고 보장되는 객체에서만 설정해야합니다. 

     

    5. 그럼 각각은 언제 쓰일까요?

     

    - strong : ARC로 인한 메모리 해제를 피하고, 객체를 안전하게 사용하고자 할때 쓰입니다.

    - weak: retain cycle을 막기 위해 사용되며, delegate 패턴이 있습니다.

    특히 weak은 위 블로그를 참고해 아파트와 입주민 관계로 설명할 수 있고, 이때 입주민이 weak으로 선언됩니다.

    이유 : Apple : 다른 인스턴스의 수명이 더 짧은 경우 즉, 다른 인스턴스를 먼저 할당 해제 할 수있는 경우 약한 참조를 사용합니다.

    - unowned : 내가 unowned 로 가지고 있는 객체는 나보다 먼저 해제되면 안되는거다. 를 명심해서

    예시로, apple의 신용카드와 고객을 들 수 있습니다. 신용카드에서 고객이 없을수는 없겠죠? 

     

    Tip:  Swift5.0에서는 unowned가 optinal로 선언될 수 있게 되었습니다~

     

     

    출처: https://zeddios.tistory.com/1213 [ZeddiOS]

    728x90

    댓글

Designed by Tistory.