Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- Protocol
- 스위프트
- 리펙토링
- SWIFT
- HIG
- Refactoring
- ios
- uitableview
- Clean Code
- 클린 코드
- ribs
- UITextView
- collectionview
- UICollectionView
- RxCocoa
- Human interface guide
- swiftUI
- 리팩토링
- MVVM
- map
- tableView
- clean architecture
- swift documentation
- rxswift
- Observable
- 애니메이션
- 리펙터링
- Xcode
- uiscrollview
- combine
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] nib, xib, Placeholders, Files's Owner, First Responder, Responder Chain 개념 본문
iOS 기본 (swift)
[iOS - swift] nib, xib, Placeholders, Files's Owner, First Responder, Responder Chain 개념
jake-kim 2021. 1. 23. 02:44nib, xib란?
- nib(NeXT Interface Builder): 뷰의 layout, display등의 요소들을 object graph로 만들어서 직렬화한 파일
- 인터페이스 빌더에서 구성한 모든 정보는 .xib파일(XML Interface Builder)라는 파일로 저장
- 프로젝트 컴파일 시 바이너리파일인 .nib파일이 되는 것
* Interface Builder란? 코딩과 상반되는 개념인 그래픽 사용자 인터페이스
nib파일
- 앱에 nib 파일이 로드되면 Cocoa는 Xcode에서 만든 객체들의 전체 객체 그래프(뷰, 컨트롤, 셀, 메뉴, 객체 모두 포함)를 재생성
- top-level객체 - 부모 객체를 가지지 않는 것들 (윈도우, 메뉴 바, 커스텀 객체) 단, Placeholder객체와 File's Owner객체는 다른 것을 주의
nib파일의 loading 과정
- 메모리에 Nib 파일의 컨텐츠와 참조된 모든 리소스 파일(객체 그래프)를 로드: 이미지와 사운드는 Cocoa 캐시에 추가됨
- nib 객체 그래프 데이터를 Unarchive하고 객체들을 초기화
- nib 파일의 객체들간에 모든 연결(Action, Oulet, Binding)이 재생성 (File's Owner와 다른 Placeholder객체들간의 연결 포함)
- Cocoa는 outlet이름과 일치하는 인스턴스 변수를 찾음
- outlet을 설정하면 등록된 모든 observer에 대한 Key-value observing(KVO) Notification이 생성
- awakeFromNib 메서드가 불려지기 전에 발생 - nib 파일에 "Vislable at launch time" 속성을 사용하도록 설정한 모든 윈도우를 표시
nib 로드 방법
* 로드한다는 의미: 코드에서 .xib파일들을 생성하여 참조한다는 의미
아래 1번과 2번 중 2번(객체를 사용한 방법) 사용 권장 (2번은 Unarchive -- 캐시되고 있는 형태)
1) Bundle 클래스의 loadNibNamed(_:owner:options:)로 로드방법
- nib 파일을 이름으로 찾아서 메모리에 로드하여, nib파일 내의 top-level 객체들을 [Any]? 타입으로 반환
- loadNib에서 first로 호출 하는이유는, placholder에서 여러개의 view를 가질 수 있기 때문
// 편리하게 UIView를 extension하여 사용
extension UIView {
// nib 로부터 view 객체 생성하는 함수
private func loadView(nibName: String) -> UIView? {
let loadNib = Bundle.main.loadNibNamed(nibName, owner: self, options: nil)
guard let view = loadNib?.first as? UIView else { return nil }
return view
}
// nib파일을 얻은 view를 세팅하는 함수
public func xibSetup(nibName: String) {
guard let view = loadView(nibName: nibName) else {
return
}
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = bounds
addSubview(view)
view.fillToSuperview() // anchor로 layout지정하는 custom 함수
}
}
2) UINib 클래스 사용
extension: UIView {
func loadViewFromNib(nib: String) -> UIView? {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: nib, bundle: bundle)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
func xibSetup() {
guard let view = loadViewFromNib(nib: type(of: self).className) else {
return
}
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = bounds
addSubview(view)
view.fillToSuperview()
}
}
// className으로 이름 얻는 extension
public extension NSObject {
var className: String {
return String(describing: type(of: self))
}
class var className: String {
return String(describing: self)
}
}
nib 초기화 관련 메소드
- awakeFromNib(): nib파일의 내용을 읽어서 object graph를 복원할 때 모든 복원이 완료된 후 nib 파일 내의 모든 객체가 받게되는 메세지 (IBOutlet등의 참조가 완료되었다는 의미)
- init(nibName:bundle:) - nib 파일로부터 뷰 컨트롤러를 생성할 때 사용, nib파일은 아직 로딩 x
- init(coder:) - nib 파일을 읽어들여서 그 데이터로부터 뷰 컨트롤러, 내부 뷰 들을 생성할 때 사용
- prepareForInterfaceBuilder() - IB에서 속성을 변경할 때 해당 코드가 내부적으로 호출되며, 실시간으로 변경된 값을 확인할 수 있는 요소
- cf) init(frame:) - nib가 아닌 코드를 통해 객체를 초기화할 때 layout과 함께 초기화 해주는 코드
Placeholders, File's Owner 객체, First Responder 객체
- Placeholders: 의미 그대로 UIView처럼 보여지는 주요 요소가 아닌, 빠져있는 것을 대신하여 연결해주는 역할을 의미
- File's Owner 객체: nib 파일을 앱코드와 연결시켜주는 객체 (nib파일의 내용을 책임지는 컨트롤러)
- nib파일(customView생성 시 .xib파일)을 로드할 때 File's Owner객체를 보고 지정한 대체 객체를 생성하여 nib파일에서 해당 객체들을 참조 할 수 있도록 하는 개념
- File's Owner객체에서 nib파일에 저장된 top-level 객체의 참조를 유지하기 위해서 사용하는 것이 @IBOutlet - First Responder 객체: Responder 객체가 이벤트를 받으면 이를 처리하거나 다른 Responder객체에게 처리할 수 있도록 넘겨야할 의무가 존재, UIKit은 적절한 Responder를 지정해서 이벤트를 넘겨서 처리하는데, 처음으로 이벤트를 받는 Responder를 First Responder로 지칭
- first responder 연관된 Hitest개념: 참고 - Responder Chain란:
- 앱은 reponder객체를 사용하여 이벤트를 받고 그 이벤트를 다룸
- responder 객체는 UIResponder 클래스의 인스턴스이며 UIView, UIViewController를 포함한 서브 클래스
- 앱이 이벤트를 받을 경우 UIKit은 first responder라고 불리는 적절한 응답자 객체에게 해당 이벤트를 전송
- UIKit은 정의된 규칙에 의해 다뤄지지 않은 이벤트들을 앱의 리스폰더 객체인 Responder Chain에 의하여, 이벤트를 처리할 수 있는 Responder가 나올때까지 responder끼리 전달
- Responder Chain을 다루는 예시) dataTextField.becomeFirstResponder()
- Responder Chain의 전환
- UIView: view가 View Controller의 rootView인 경우, 다음 reponder는 ViewController
- UIViewController: ViewController가 윈도우의 root view라면 다음 responder는 window 객체
- UIWindow: UIWindow의 다음 responder는 UIApplication 객체
- UIApplication: 다음 responder는 AppDelegate
* 참고문서:
'iOS 기본 (swift)' 카테고리의 다른 글
[iOS - swift] 화면 전체의 Interaction을 off, on 방법 (0) | 2021.01.24 |
---|---|
[iOS - swift] UIWindow, makeKeyAndVisible() (0) | 2021.01.24 |
[iOS - swift] Optional binding, Optional Chaining (0) | 2021.01.14 |
[iOS - swift] stored property(저장 프로퍼티)와 computed property(계산 프로퍼티) (0) | 2021.01.13 |
[iOS - swift] enum 사용 방법 (String -> enum 매핑, 타입 사용 방법) (0) | 2021.01.13 |
Comments