iOS/UIKit

[UIKit] Interface Builder Outlet 연결 Strong || Weak

kyxxn 2024. 1. 24. 13:11
728x90

View는 스토리보드 <-> 코드간의 연결을 위해 @IBOutlet을 통해 해결한다.

스토리보드에서 Ctrl + 좌클릭으로 UI 객체를 코드에 끌어놓으면 다음과 같이 자동으로 생성해준다.

위 사진에서 알 수 있는 점

1. Outlet 연결됨

2. 변수 명을 입력할 수 있음

3. Storage를 'Strong'과 'Weak' 중에 고를 수 있고, Default는 Weak임'

4. UI 객체는 내가 Ctrl + 좌클릭으로 가져온 Type으로 자동 선정됨

 

변수 명을 입력하면 알아서 '@IBOutlet weak var myLabel : UILabel!'로 선언된다.

3번에서 말한 Strong과 Weak는 강한 참조, 약한 참조로 ARC와 관련이 있다.

 

클래스의 인스턴스는 힙 영역에 저장되고, 이는 ARC에 의해 참조 횟수에 따라 메모리 관리가 되는데

weak 키워드를 붙여 클래스의 인스턴스를 생성하면 '약한 참조 타입'으로 RC가 증가되지 않는다.

반면, weak를 사용하지 않고 그냥 다른 키워드 없이 클래스의 인스턴스를 생성하면 RC가 1 증가되어 참조 횟수가 증가된다.

 

왜 Default로 Weak가 사용될까 ?

ViewController가 weak가 아닌 strong으로 UI객체를 참조하면 안되는 건가 ?

두 경우에 대해 그림을 그리면 다음과 같다.

모든 ViewController는 자신이 관리하는 view를 하나씩 강한 참조로 갖고 있는다.

view 위에 뷰 객체들이 올라오니 ViewController와 view는 항상 강한참조 되어 있음

view는 자신의 하위 뷰 객체들과 강한 참조를 유지한다.

즉, 개발자가 스토리보드에 올린 뷰 객체는 RC가 1개씩 있음

 

뷰 객체들은 ViewController의 인스턴스에 저장되는 것이 아닌, 각자의 힙 영역에 저장되고 IBOutlet으로 ViewController와 연결되면 ViewController는 Outlet 변수로 각 뷰 객체의 참조를 저장하는 방식

 

1. Strong으로 뷰 객체를 참조한 경우

  • ViewController는 View를 강한 참조      ->  View의 RC : 1
  • View는 뷰 객체를 강한 참조                    -> 뷰 객체의 RC : 1
  • ViewController는 뷰 객체를 강한 참조   -> 뷰 객체의 RC : 2

2. Weak로 뷰 객체를 참조한 경우

  • ViewController는 View를 강한 참조      ->  View의 RC : 1
  • View는 뷰 객체를 강한 참조                    -> 뷰 객체의 RC : 1
  • ViewController는 뷰 객체를 약한 참조   -> 뷰 객체의 RC : 1

 

여기까지 두 상황에 대해 이해했다.

그러면 Strong 참조일 때 메모리 누수가 발생할까 ?

dealloc 되는 상황을 알아보자

ViewController가 뷰객체를 Strong 참조할 때, VC가 dealloc 된다면 ?

현재 RC의 상황

- ViewController : 1

- View : 1

- View Objects : 2

 

1. ViewController가 dealloc 되므로 View의 RC가 1 감소함    ->  View의 RC : 0

2. Label을 소유하던 View가 dealloc 되니 Label의 RC도 1 감소함 -> View : dealloc,  Label 뷰객체의 RC : 1

3. ViewController가 dealloc 되니 Label의 RC도 1 감소함  -> View : dealloc, Label 뷰객체의 RC : dealloc

 

깔끔하게 모두 dealloc이 됨

즉, IBOutlet에 Strong 쓴다고 문제는 되지 않음

 

그럼 맨날 Stroage를 Strong으로 하면 됨 ?

Strong 참조에 의한 메모리 누수 발생

앱을 사용하다보면 메모리 부족 현상이 발생할 수 있다.

메모리 부족 현상이 생길 경우 ViewController의 'didReceiveMemoryWarning' 메소드가 호출된다.

위 메소드는 부족한 메모리 확보를 위해 ViewController의 내부 Main View를 nil 처리해서 지워버린다. (나중에 필요하면 다시 생성됨)

Main View를 메모리에서 해제 시키면 Sub View들이 모두 dealloc되어 버린다는 의미

 

그러나 Strong으로 SubView(뷰객체)를 갖고 있다면, ViewController가 Strong으로 갖는 RC 1에 의해 지워지지 않는다.

즉, 부모 View가 nil이어도 Sub View는 dealloc 되지 않는다.

SubView는 어차피 보이지 않는 화면인데 존재해봤자 메모리 누수 !

 

그럼 언제 Strong으로 연결하는가 ?

IBOutlet 변수에 Strong 참조를 해야하는 경우

바로 위세어 ViewController가 메모리 부족하면 View를 nil 시켜버린다는 것을 알았다.

그럼 그에 맞게 didReceiveMomoryWarning() 메소드가 호출되어도 뷰 객체가 해제되지 않길 원할 때 사용하면 된다.

 

혹은, 뷰 객체가 메모리에서 해제되는 시점을 제어하고 싶을 때 사용하거나 복잡한 뷰객체 계층구조를 가졌을 때 사용하면 좋다고 한다.

 


참고

https://monibu1548.github.io/2018/05/03/iboutlet-strong-weak/

 

Interface Builder IBOutlet연결에 Strong과 Weak 어떤것을 써야할까? - JingyuJung's Blog

IBOutlet의 Strong vs Weak Interface Builder를 사용하는 프로젝트에서 View를 코드상에서 제어하기 위해 IBOutlet으로 스토리보드 <-> 코드 를 연결하게 됩니다. Ctrl키를 누르고 View를 .m 또는 .h 파일로 가져오

monibu1548.github.io

https://co-dong.tistory.com/60

 

iOS) IBOutlet연결 Strong VS Weak

스토리보드에서 작업한 UI객체를 코드에 연결하기 위해서는 IBOutlet 또는 IBAction을 사용하여 연결해야 한다. IB는 Interface Builder의 줄임말입니다. 스토리보드에서 control + 드래그를 사용하여 코드에

co-dong.tistory.com