스토리보드 요소가 Nib으로 다뤄지는 과정 (feat. awakeFromNib)

J.Noma·2021년 12월 13일
3

iOS : Xcode

목록 보기
2/3

StackOverflow: awakeFromNib, outlets and storyboards: is the documentation wrong?


🐶 스토리보드를 컴파일하면

우리가 Xcode에서 App을 빌드할 때, 스토리보드를 컴파일하는 과정을 거치게 됩니다
그리고, 스토리보드 컴파일 결과물로 아래와 같이 Info.plist.nib파일들이 들어있는 package를 얻게 됩니다

:; pwd
/Users/mayoff/Library/<snip>/Pinner.app/Base.lproj/Main.storyboardc
:; ll
total 80
drwxr-xr-x  10 mayoff  staff   340 May 11 22:13 ./
drwxr-xr-x   4 mayoff  staff   136 May 11 22:13 ../
-rw-r--r--   1 mayoff  staff  1700 May 11 22:13 AccountCollection.nib
-rw-r--r--   1 mayoff  staff  1110 May 11 22:13 AccountEditor.nib
-rw-r--r--   1 mayoff  staff  2999 May 11 22:13 BYZ-38-t0r-view-8bC-Xf-vdC.nib
-rw-r--r--   1 mayoff  staff   439 May 11 22:13 Info.plist
-rw-r--r--   1 mayoff  staff  7621 May 11 22:13 LqH-9K-CeF-view-OwT-Ts-HoG.nib
-rw-r--r--   1 mayoff  staff  6570 May 11 22:13 OZq-QF-pn5-view-xSR-gK-reL.nib
-rw-r--r--   1 mayoff  staff  2473 May 11 22:13 UINavigationController-ZKB-z3-xgf.nib
-rw-r--r--   1 mayoff  staff   847 May 11 22:13 UIPageViewController-ufv-JN-y6U.nib

🐱 Info.plist

Info.plist는 스토리보드의 scene 중 특정 조건에 부합하는 scene과 이에 대응되는 Nib파일이름이 포함됩니다
특정 조건이란, 스토리보드 ID를 가졌거나, Segue의 destination이거나, root scene에 해당하는 경우에만 Info.plist에 포함됩니다

:; plutil -p Info.plist 
{
  "UIViewControllerIdentifiersToNibNames" => {
    "AccountCollection" => "AccountCollection"
    "UINavigationController-ZKB-z3-xgf" => "UINavigationController-ZKB-z3-xgf"
    "UIPageViewController-ufv-JN-y6U" => "UIPageViewController-ufv-JN-y6U"
    "AccountEditor" => "AccountEditor"
  }
  "UIStoryboardDesignatedEntryPointIdentifier" => "UINavigationController-ZKB-z3-xgf"
  "UIStoryboardVersion" => 1
}

🐭 Nib 파일

이제 본격적으로 Nib 파일에 대한 이야기를 해보겠습니다

결론부터 말하면, 스토리보드 컴파일의 결과로 만들어지는 Nib 파일의 종류는 2가지입니다

  • (1) Scene의 top-level object만을 저장하는 Nib
  • (2) subview 계층을 저장하는 Nib

1. Scene의 top-level object만을 저장하는 Nib

◼ 위에서 설명한 Info.plist에 저장되는 Nib을 말합니다
이 nib 파일들은 대응되는 scene에 대한 top-level object 정보를 포함하고 있습니다
(뷰컨이 바로 top-level object에 해당됩니다)

◼ 위 예시에서 보이는 AccountCollection.nib / AccountEditor.nib 같은 일반적인 이름의 Nib에 해당합니다

◼ 그리고, 'subview 계층을 저장하는 Nib 파일'의 이름을 가지고 있습니다

:; strings - AccountCollection.nib |grep -e '-.*-'
UIPageViewController-ufv-JN-y6U
BYZ-38-t0r-view-8bC-Xf-vdC          <---------
UpstreamPlaceholder-5Hn-fK-fqQ
UpstreamPlaceholder-8GL-mk-Rao
q1g-aL-SLo.title

2. subview 계층을 저장하는 Nib

◼ subview 계층은 별도의 nib 파일에 들어 있습니다

◼ 이 nib 파일의 네이밍은 '뷰컨 ID'과 'top-level subview의 ID'로 지정됩니다
(참고로, object ID는 'Identity Inspector'에서 확인할 수 있습니다)

예로, 'AccountCollection'이라는 scene의 뷰컨 ID가 BYZ-38-t0r이고, 뷰컨 내 top-level view의 ID가 8bC-Xf-vdC라고 가정해봅시다
이 scene의 view 계층의 nib 파일이름은 이 둘을 합친 BYZ-38-t0r-view-8bC-Xf-vdC.nib가 됩니다

◼ 만약 scene이 subview 계층을 가지고 있지 않다면, 뷰컨에 대한 Nib만 갖고 subview 계층에 대한 Nib은 없을 것입니다


🦊 뷰컨과 Subview 계층의 awakeFromNib() 결과가 서로 다르다?

✔️ awakeFromNib()란

Nib file을 소스로 생성되는 객체는 초기화가 완료되면 이 메서드를 호출하게 됩니다

즉, 원래 awakeFromNib() 메서드가 호출된 시점에는 자신이 가진 IBOutlet들이 모두 초기화된 후 연결되어 접근이 가능한 상태여야 합니다

✔️ 뷰컨의 awakeFromNib() 시점에는 IBOutlet에 접근불가?

우리가 스토리보드에서 뷰컨 내에 구성한 view들은 awakeFromNib()가 호출된 시점에 subview까지 전부 정상적으로 초기화되어 자신의 outlet/action에 접근이 가능합니다

하지만, 뷰컨awakeFromNib() 시점에는 outlet/action에 접근이 불가합니다.
이는 위에서 설명한 awakeFromNib()의 정의에 어긋납니다. 왜 이런 걸까요?

✔️ 뷰컨과 Subview 계층의 Nib 파일이 분리되어 있고 사용시점이 다르다

App이 스토리보드로부터 scene을 로드할 때, 뷰컨같은 top-level object Nib를 로딩합니다

이 때, Nib 로더는 top-level object Nib만 로딩하고 그에 속한 subview 계층 Nib는 로딩하지 않은 채 awakeFromNib() 메시지를 전달하게 됩니다

그래서 뷰컨의 awakeFromNib() 시점에는 outlet/action같은 subview 계층들이 초기화되지 않은 상태인 것입니다

subview 계층의 Nib 파일은 이후에 뷰컨이 loadView() 메서드를 통해 view 프로퍼티에 대한 요청이 올때서야 비로소 로드됩니다
이 과정에서 instantiateWithOwner() 메서드를 통해 subview를 Nib으로부터 unarchiving하고 subview 계층 object들을 owner인 뷰컨의 outlet/action에 연결하게 됩니다
Nib 로더가 subview 계층 Nib 로딩을 끝내면, awakeFromNib() 메시지를 subview 계층 object들에게 전달하게 됩니다

instantiateWithOwner()가 종료되면 뷰컨에게 viewDidLoad()에 대한 메시지가 전달됩니다

profile
노션으로 이사갑니다 https://tungsten-run-778.notion.site/Study-Archive-98e51c3793684d428070695d5722d1fe

0개의 댓글