나의 발자취

iOS App View Hierarchy (iOS앱 뷰 계층), @IBOutlet 연결하는 이유 본문

앱 개발/iOS

iOS App View Hierarchy (iOS앱 뷰 계층), @IBOutlet 연결하는 이유

달모드 2024. 8. 29. 14:24

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으로 옵셔널 언래핑을 해준다. 

 

 

 

728x90
반응형
Comments