DEV Community

Ingun 전인건
Ingun 전인건

Posted on

4

UIView 는 File’s Owner 가 될 수 없어요

재사용 가능한 .xib를 만들때 UIView 를 File’s owner 로 설정하는 방법이 널리 퍼져있어요. 사실 이게 잘못된 방법인데 잘 작동하니깐 사람들이 모르고 쓰는것 같아서 이걸 바로잡고자 이 글을 써봤어요.

애플 개발자 문서 를 보시면 File’s owner를 다음과같이 설명하고 있어요

Typically, you use outlets in the File’s Owner object to store references to the top-level objects of a nib file.

top-level object 가 뭐냐고요? 같은 문서 밑에 보시면 top-level object에 대해 다음과같이 또 써있어요:

The top-level objects are the subset of these objects that do not have a parent object. The top-level objects typically include only the windows, menu bars, and custom controller objects that you add to the nib file.

설명대로라면 UIView 가 File’s owner 로써 알맞는 후보가 아니라는걸 알 수 있어요. UIView 는 부모 오브젝트가 없다는 점은 만족하죠(.xib 파일에는 UIView 가 최상위 오브젝트니까요) 하지만 windows 도 아니고 menu bars 도 아니고 controller object 도 아니에요.

문서상으로는 그렇다고 쳐도 잘 작동 하니깐 장땡 아니냐고요?

진짜 잘 작동 하는걸까요?

절대 아니에요. UIView 를 File’s owner 로 설정하면 어떤 문제점들이 생기는지 설명드릴게요

UIView 를 File’s owner 로 쓴다는 아이디어 자체가 구조적으로 모순이에요. .xib 파일은 원래 다양한 UIView 타입의 오브젝트들을 가지고 있을 수 있게끔 만들어졌어요. 근데 생각해보면 .xib 파일은 단 하나의 File’s owner 만을 가질 수 있잖아요? 그렇다면 .xib 파일은 하나의 UIView 타입이면서 동시에 다수의 UIView 타입일 수 있다는 말이되잖아요? 모순이죠.

이 모순은 악마를 하나 낳아요. 바로 contentView 에요. 첫째로 contentView는 프로그래머가 모든 뷰를 자기 아래로 정렬시키는 노가다를 하게 만들어요. 결과적으로 뷰의 어떠한 컴포넌트를 접근하든 contentView.-를 써서 자기 자신을 거치게 만들어요. 이놈만 없었다면 편하고 자연스러운self 를 쓸 수 있었을텐데 말이죠. 그뿐만이 아니에요. 이 악마때문에 UI 구조랑 일치하는 자료구조를 정의할 수가 없어요. Declarative UI 로발전하고있는 이 시점에 시대를 역행하게 만들죠.

재사용 가능한 .xib를 만드는 옳은 방법

샘플 프로젝트를 만들어 볼게요

이게 기존의 잘못된 구조에요:

Alt Text

우리는 다음과같은 새로운, 옳은 구조를 쓸거에요:

Alt Text

차이점으로는

  • File’s owner는 공석으로 냅둘거에요
  • MyView 는 File’s owner 가 아닌 object class 로써 outlet 들을 제공할거에요
  • contentView 는 사라지리거에요
  • 여전히 storyboard 에서 쓸 수 있을거고, 코드에서 인스턴스화 할 수 있을거에요
  • .xib파일에 여러개의 view 오브젝트들을 정의할 수 있을거에요.

샘플프로젝트는 깃헙에 올려놓았어요:

MyView 라는 클래스를 하나 정의해보아요

class MyView: UIView {
    @IBOutlet weak var subView1:UIView!
    @IBOutlet weak var subView2:UIView!

    //This is helper function so you can instantiate MyView like
    //let view = MyView.loadViewFromNib()
    static func loadViewFromNib() -> MyView {
        let bundle = Bundle(for: self)
        let nib = UINib(nibName: "MyViews", bundle: bundle) //“MyViews” is name of xib file
        return nib.instantiate(withOwner: nil, options: nil).first {
            ($0 as? UIView)?.restorationIdentifier == "1"
        }! as! MyView //You will set restorationIdentifier later
    }
}
Enter fullscreen mode Exit fullscreen mode

outlet 들이랑 .xib파일 도 하나 만들고, 자식 뷰도 몇개 만들고 MyView 로 세팅 해봅시다

Alt Text

Outlet 을 연결하고

Alt Text

Restoration id 도 설정하세요. 이건 xib 에 있는 뷰들을 구별하기위한 id 에요. 뷰 오브젝트가 하나만 존재한다면 굳이 안써도 돼요.

Alt Text

이제 코드에서 다음과같이 인스턴스화 할 수 있어요.

let view = MyView.loadViewFromNib()
Enter fullscreen mode Exit fullscreen mode

이제 스토리보드에서 쓰는 방법을 알아볼건데 그전에 먼저 말하고싶은게 있어요. contentView 를 쓸거에요. 아까 contentView 를 악마라고 까놓고선 이제와서 또 쓰는건 무슨 위선 이냐고 생각할 수 있는데 그렇지 않아요. 이번에 쓰는 contentView 는 기존의것과 많이 다른거에요. 이번거는 기존의 hack 이나 ad-hoc 같은 용도의 contentVew 가 아니에요. 바로 modularization of storyboard adaptation 라는 사명을 가진 뷰랍니다. 말 그대로 스토리보드 어댑터의 역할을 하는 모듈이죠. 그리고 이번거는 프로그래머의 앞길을 가로막지 않을거에요. 다음과같은 특징이 있기 때문이죠

  • 이번 contentView 는 오로지 코드상으로만 존재해요. UI 빌더 상의 정의를 필요로 하지 않죠. 다른말로 .xib 파일이나 .storyboard파일을 건들지 않아요.
  • 더 나아가서 이번 contentView 는 MyView 클래스에서 완전히 모듈화 돼서 떨어져 나가요. 위에서 말한 스토리보드 어댑터 역할을 하는 클래스로 따로 정의돼요. 이해가 안간다면 이따가 보여드릴 샘플을 보면 이해가 가실거에요
  • 다른 클래스로 모듈화가 되었으니, 기존 contentView 처럼 자료구조를 방해할 일이 없겠죠? 이제 뷰의 property 에 접근할때마다contentView.- 를 쓸 일이 없을거에요

이제 스토리보드에서 쓰는 방법을 알아봅시다

어댑터 클래스를 정의해요

class StoryMyView1:UIView {
    var contentView:MyView
    required init?(coder aDecoder: NSCoder) {
        contentView = MyView.loadViewFromNib()
        super.init(coder: aDecoder)
        contentView.frame = bounds
        addSubview(contentView)
    }
}
Enter fullscreen mode Exit fullscreen mode

끝났어요 이제 .storyboard UI 빌더에서 다음과 같이 쓰면 돼요.

Alt Text

다음과같이 한 xib 파일에 여러개의 view 를 정의할 수 있다는 점도 잊지말고요

Alt Text

Alt Text

Sentry mobile image

Tired of users complaining about slow app loading and janky UI?

Improve performance with key strategies like TTID/TTFD & app start analysis.

Read the blog post

Top comments (0)

Sentry mobile image

App store rankings love fast apps - mobile vitals can help you get there

Slow startup times, UI hangs, and frozen frames frustrate users—but they’re also fixable. Mobile Vitals help you measure and understand these performance issues so you can optimize your app’s speed and responsiveness. Learn how to use them to reduce friction and improve user experience.

Read full post →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay