나의 발자취
iOS App View Hierarchy (iOS앱 뷰 계층), @IBOutlet 연결하는 이유 본문
iOS App View Hierarchy
Storyboard 기준으로, ViewController에 직접 뷰를 나타내면서 iOS 앱의 View 계층과 각 용어들에 대해 의미를 알아야 할 필요가 있다.
상관관계를 잘 이해할 수 있도록 순차적으로 설명을 하겠다. 일단 쉽고 제일 필수적인 'View' 부터!
- ViewView는 윈도우에 그릴 수 있는, user action에 반응할 수 있는 직사각형 영역을 말한다.
즉, 1) 시각적으로 보여지고 2) 사용자 행동에 반응 3) 반응형 객체 이벤트 핸들링 4) content 출력의 역할을 한다.
View는 직/간접적으로 NSView(Mac OSX) 혹은 UIView(iOS)를 상속받는다. AppKit, UIKit 프레임워크는 어플리케이션의 윈도우에 보이는 거의 모든 뷰(버튼, 테이블 뷰, 텍스트 필드, 툴바, 슬라이더 등)들을 제공한다.
이 UIView/NSView를 클래스의 하위 속성으로 만들어서 커스텀 뷰를 만들수도 있다.
뷰들은 서로 상관관계를 가지고 있는데, 여기서 Superview, Subview, Window 속성이라는 용어가 나온다!!
- Window -해당 뷰의 모든 계층구조를 계승하는 백그라운드 뷰를 말한다.iOS 앱에서 window는 view라고 할 수 있다. (UIWindow는 UIView를 상속하기 때문)
- RootView - 윈도우 밑에 RootView를 가지고 있다. (위 이미지에서는 RootView = MainView) 각 뷰는 자기의 RootView를 가지고 있고, VC에 의해 RootView가 교체당하면서 뷰가 전환되게 된다.
- SuperView
- SubView
우리는 새로운 UI를 생성하기 위해 기존 뷰(superview)에 새로운 뷰(subview)를 추가한다.
코드 스니펫
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// ⭐️ View 객체(인스턴스) 생성
let view1 = UIView() // root view 이름이 'view'라서
// 레이아웃 생성
view1.frame = CGRect(x: 100, y: 100, width: 200, height: 100) // CG: CoreGraphics
// 배경색 지정
view1.backgroundColor = UIColor(red: 0.23, green: 0.1, blue: 0.30, alpha: 0.5)
// 모든 뷰들은 Root View에 속하던지, Root View에 속한 뷰에 속해야 함.안그럼 안나옴.
view.addSubview(view1)
// ⭐️ UILabel 생성
let label1 = UILabel()
label1.frame = CGRect(x: 100, y: 200, width: 200, height: 50)
label1.text = "Hello World!"
label1.font = UIFont.systemFont(ofSize: 30)
view.addSubview(label1)
}
}
ViewController LifeCycle
UIViewController에 정의되어있다.
스토리보드 Main뷰에 Label 객체를 만들고 @IBOutlet으로 연결하는 이유
지금 인스턴스가 생성되었으므로 Label은 Heap 영역에 만들어져있다. -> 위와 달리, 위에서는 view1, label1이라는 참조변수를 만들어서 접근해 값을 변경했지만
스토리보드로 Label을 생성하여 GUI를 통해 배치를 시키면 방금 말한대로 인스턴스가 생성되었을 뿐 접근할 수 없다. (참조변수가 생성되지 않았으므로)
-> 따라서 프로퍼티가 위치해야 할 곳 (ViewController 클래스 내부) 에다가 위치를 올려놓고 맵핑을 해준다.
@IBOutlet weak var label2: UILabel! 의 의미
- @IBOutlet - Interface Builder UI 컴포넌트이다. 참조변수의 역할! 연결이 활성화되면 왼쪽에 🔘 버튼이 보인다.
- weak - 참조 타입이 약하다는 것 (참조타입은 weak / strong이 있다.)
- var label2: UILabel - label2의 타입은 UILabel이다.
- ! - 생성자가 없고, 객체이기 때문에 값을 넣어줄수도 없어서 '나중에 값을 꼭 넣어준다고 약속하는 의미'로 옵셔널 강제해제 타입인 것이다.
인스펙터 창 (디자인 타입) 설정 vs 코드 (런타입) 설정의 차이점?
- 디자인 타입: 안바뀌는 내용이면 디자인 타입으로 디자인 요소를 설정하면 된다.
- 런타입: 바뀌는 내용(요소)인 경우에는 코드에서 설정하면 된다.
sender: Any vs sender: UIButton 차이점
버튼을 버튼의 용도뿐만 아니라 여러가지 이벤트 핸들러로 사용하고 싶을 때에는 sender: Any로 정하면 된다. 이렇게 정하고 나서 Button으로 사용하려고 하면, 다운캐스트를 해야한다. let btn = sender as UIButton 에서, 옵셔널값일 수 있으므로 as 뒤에 ?를 붙여준다. 그리고 옵셔널이므로 if-let으로 옵셔널 언래핑을 해준다.
'앱 개발 > iOS' 카테고리의 다른 글
UI 컴포넌트 실습 (UISegmentedControl, UITextField, UISlider, UISwitch, UIStepper) (0) | 2024.08.29 |
---|---|
ViewController LifeCycle (2) | 2024.08.29 |
Optional Chaining, UIColor ColorLiteral (0) | 2023.12.14 |
iOS 앱 생명주기 (0) | 2023.10.07 |
iOS 파일시스템 이해하기 (1) | 2023.10.07 |