iOS/Swift

[Swift] @IBOutlet weak var myLabel: UILabel! 에 대해 알아보자

2024. 3. 21. 13:07

1. @IBOutlet? @IBAction?

 

먼저, IB는 Interface Builder의 약자로 Xcode에서는 스토리보드를 말한다.

- @IBOutlet: 스토리보드에서 생성한 뷰객체를 코드와 연결하여 변수 정의

- @IBAction: 스토리보드에서 생성한 뷰객체를 코드와 연결하여 객체에 특정 Event가 일어났을때 호출할 함수 정의

즉 두 키워드는 스토리보드와 코드를 연결시키는 역할이다.

 

2. weak?

 

@IBOutlet 연결시 Storage 기본값은 weak으로 설정되어있다. 왜 weak으로 선언할까?

View Controller 객체는 기본적으로 View 객체를 갖는다. 그리고 UI를 구성하는 UILabel, UIImageView 등의 하위 뷰객체들은 이 UIView 위에 올라간다.

View Controller는 자신의 UIView에 대해 강한 참조를 유지하고, UIView는 하위 뷰객체들에 대해 강한 참조를 유지한다.

이때 하위 뷰객체들과 View Controller가 @IBOutlet을 통해 연결되면, View Controller가 하위 뷰객체들에 대해 참조를 저장하게 되는데, 다음과 같이 RC를 갖는다.

 

- strong 으로 연결된다면,

VC가 View를 강하게 참조하고, VC와 View가 subView를 강하게 참조하므로, View_RC: 1 / subView_RC: 2

- weak으로 연결된다면,

VC가 View를 강하게 참조하고, View가 subView를 강하게 참조하므로, View_RC: 1 / subView_RC: 1

 

두 경우 모두 VC가 메모리에서 정상적으로 해제되었을때 View, subView까지 잘 해제되므로 메모리 누수는 일어나지 않는다.

그렇다면 왜 weak을 쓸까?

바로 메모리가 부족한 경우 때문이다.

메모리가 부족할때, VC는 didRecieveMemoryWarning 함수를 호출한다. 이 함수는 View에 nil을 할당하여 View와 함께 subView들까지 메모리에서 해제시켜 메모리를 확보한다. 그런데 이때 @IBOutlet이 strong으로 연결되어 있다면, View가 해제되어도 subView는 VC의 강한 참조로 인해 RC 1을 유지하기 때문에 메모리에서 해제되지 않는다. 보이지 않는 뷰임에도 메모리를 차지하게 되는 것이다.

 

@IBOutlet에 strong을 써야 하는 경우도 있다고 한다. 복잡한 뷰 Hierechy 구조상에서 subView를 사용해야 하는 경우이다. 모든 연결이 weak이라면 중간쯤 있는 View가 어떤 이유로 메모리에서 해제되었을때 그 하위뷰들도 함께 해제되어 필요한 subView를 사용하지 못하게 된다. 이런 경우는 많지는 않으니.. 결론적으로 일반적인 상황에서는 weak을 쓰면 된다!

 

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

 

 

3. var myLabel: UILabel! ?

 

@IBOutlet으로 연결된 변수는 모두 SomeType! 형태인 것을 볼 수 있다.

이는 옵셔널 타입 중 하나로, IUO(암시적 추출 옵셔널) 타입이라 부른다.

IUO 타입은 값이 있는 경우 따로 언래핑 처리를 해주지 않아도 강제 언래핑되어 값을 사용할 수 있는 타입이다.

이러한 특징을 제외하곤 일반적인 옵셔널 타입과 거의 동일하다.

 

1. 느낌표(!)를 붙여 타입을 선언하며, 값 또는 nil을 할당할 수 있다.

var name: String! = nil
name = "eqqmayo"

 

2. 일반적인 옵셔널 타입처럼 옵셔널 바인딩, 닐 코얼레싱을 이용해 값 유무에 따라 분기처리할 수 있다.

guard let name = name else { return }
print(name)
var id: Int! = 10
print(id ?? 0)

 

3. 값이 있는 경우 정상적으로 값을 사용할 수 있지만, 값이 nil일때 접근하는 경우 강제 언래핑되어 프로그램이 비정상적으로 종료된다.

var id: Int! = 10
print(id + 5)  // 강제 언래핑되어 10 출력

id = nil
print(id + 5)  // 강제 언래핑되어 프로그램 종료

 

그렇다면 IUO 타입은 왜 사용하는 것일까?

프로그램 구조 상 특정 시점 이후 옵셔널에 값이 무조건 들어있다는 것을 명확하게 알 수 있는 경우에는, 옵셔널값에 접근할 때마다 언래핑 처리를 해주는 것이 비효율적이다. IUO 타입을 사용하면 이 언래핑 과정을 생략하여 가독성과 편리성을 높일 수 있다!

 

IUO 타입이 이용되는 대표적인 경우가 @IBOutlet이다. 스토리보드에 생성한 객체와 연결되기 전까지는 변수에 nil이 담겨있지만 연결된 시점부터는 변수가 명확히 값을 갖고 있기 때문에 IUO 타입으로 선언하는 것이 효율적이다.

 

https://babbab2.tistory.com/19

 

Swift) Optional 부수기 (4) Optional Unwrapping - IUO (옵셔널 묵시적 추출)

안녕하세요 소드립니당 🌝 어김없이 퇴근하고 포스팅 하러 왔어여 오늘은 약속이 있어서 후딱 쓰고 갈거기 때문에 내용이 짧아여 물론 길게 할 내용이 아니라서 짧게 가겠음 오늘 공부할 내용

babbab2.tistory.com