XIB를 사용한 UIView Custom 제대로 이해하기

whitelips
a day of a programmer
6 min readJun 19, 2019

#iOS #XIB #UIView #Custom #아이폰 #앱개발 #커스텀뷰

애플은 UIViewController, UITableViewCell, UICollectionViewCell의 Subclass 에만 XIB 연결을 공식적으로 지원하고 있습니다. 이에 인터넷을 검색해보면, 개발자 각자의 방법으로 UIView의 custom xib를 사용하고 있는데요. 오늘은 어디서 알려주지 않는 XIB와 UIView 코드의 의미를 설명하도록 하겠습니다.

별도로 생성한 XIB와 Custom View 코드의 연결은 크게 2가지 방법이 있습니다.

1. File’s Owner의 Custom Class 사용

Interface Builder에서 File’s Owner의 Custom Class 항목에 연결하려는 Class인 RedView를 입력하였습니다.

물론 이렇게 입력만 한다고 해서는 코드에서 바로 사용할 수는 없습니다. xib에서 구성한 View를 가져오기 위해서는 nib 형태로 불러와야 합니다.

1–1. loadNibNamed

override init(frame: CGRect) {
super.init(frame: frame)
let name = String(describing: type(of: self)
guard let loadedNib = Bundle.main.loadNibNamed(name, owner: self, options: nil) else { return }
guard let view = loadedNib.first as? UIView else { return }
view.frame = self.bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addSubview(view)
}

위 코드는 RedView class 의 init 에서 RedView.xib를 불러와서 사용하는 방법을 보여줍니다. 좀더 자세히 살펴보겠습니다.

loadNibNamed()를 호출한 후에 .first 를 통해 첫번째 항목을 사용하고 있는데, 이는 xib 에 아래 그림과 같이 여러 개의 항목을 추가할 수 있기 때문입니다.

하나의 Xib에 2개의 View가 추가되어 있습니다.

RedView.xib에서는 하나의 UIView만 사용하기에 first를 UIView로 캐스팅하여 사용하게 되었습다. 이후 불러온 view의 frame을 RedView의 bounds로 설정하고, RedView의 크기에 따라 함께 변경되도록 오토리사이징 마스크를 지정하였습니다.

1–2. UINib

override init(frame: CGRect) {
super.init(frame: frame)
let name = String(describing: type(of: self)
let nib = UINib(nibName: name, bundle: Bundle.main)
guard let view = nib.instantiate(withOwner: self, options: nil).first as? UIView else {
return }
view.frame = self.bounds
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addSubview(view)
}

여기서는 1–1에서의 loadNibNamed 대신에 UINib을 사용하였을 뿐 큰 차이는 없습니다.

2. View의 Custom Class 사용

Interface Builder에서 표시되는 View의 Custom Class 항목에 연결을 원하는 Class인 RedView를 입력하였습니다.

Xib에서 사용한 View의 Custom Class를 사용하는 경우라면, 아래와 같이 불러서 사용하여야 합니다.

let name = String(describing: RedView.self)
guard let loadedNib = Bundle.main.loadNibNamed(name, owner: self, options: nil) else { return }
guard let redView = loadedNib.first as? RedView else { return }

nib을 불러온다는 점에서는 비슷하지만, 캐스팅을 UIView가 아닌 RedView로 사용하였습니다. xib에서 구성한 View를 바로 불러서 사용한다는 점이 다르게 보입니다.

앞서 2가지의 방법은 nib을 불러오는 방식은 같지만, Custom Class를 사용하는 방법에 있어서 큰 차이를 가집니다.

특히나 1번의 방법은 Custom UIView(=RedView) 에서 xib에서 구성한 View를 추가로 불러와서 addSubView를 하는 점이 다소 View Hierarchy를 하나 더 구성하게 되어 다소 의문을 가질 수 있습니다.

그러나 아래 코드처럼 UIView의 init 생성자를 그대로 사용할 수 있어 그 이득이 있습니다.

let redView = RedView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))

단순하게 View를 구성하고 불러오는 데에 그치지 않고, Custom View의 확장성을 생각해본다면 이제 다르게 보이나요? 또한 여기에 그치지 않고, 오토레이아웃까지 고려해본다면 어떨까요?

iOS 개발을 하면서 Custom View는 정말 많이 사용하게 될텐데요. Xcode에서 자동생성되지 않아서 열심히 인터넷을 찾으면 나오는 2가지 방법. 이제는 따라하지말고 그 차이를 이해하시고 더 좋은 코드를 작성하시길 바랍니다.

-끝-

--

--

whitelips
a day of a programmer

Software Engineer with 10+ years in iOS, focusing on performance optimization, modularization, and innovative solutions. Proven leader in major tech projects.