[iOS] 커스텀 UIView - xib이용하기 (2가지 방법)

2021. 3. 6. 15:54iOS

반응형

iOS 개발을 하다보면 UIView를 커스텀으로 제작해야하는 상황이 많이 생기죠?

그때 다들 어떻게 개발하셨나요.

 

오늘은 다른 방법들도 존재하겠지만 재사용을 하기 좋고 더욱 직관적으로 뷰를 알아볼 수 있는 방법인 xib를 이용해서 커스텀 뷰를 제작하는 방법을 알아보려고 합니다.

 

그리고 xib를 이용하는 방법에는 2가지의 방법이 있는데 간단하게 차이도 보도록 하겠습니다 🙃

 

  1. File Owner에 Custom Class를 적용하는 방법
  2. UIView에 Custom Class를 적용하는 방법

 

우선 두 가지를 적용하기 전에 동일한 작업을 먼저하겠습니다!!

여기까지는 두 방법 모두 같이 해야하기 때문에, 따라해주세요.

 

먼저 UIView를 상속받은 sub class를 하나 생성해주세요.

그리고 xib 파일을 하나 선택해서 다시 생성해주세요. (이름은 위에서 생성한 UIView의 이름과 동일해야합니다.)

여기까지 완료했다면 일단 사전 작업은 완료되었습니다.

이제 각 방법에 대해 같이 사용해보고 차이를 알아보도록 하겠습니다.

 

 

File Owner Custom Class

우선은 File Owner에 Custom Class를 적용해서 본인만의 커스텀 뷰를 만드는 방법을 해보도록 하겠습니다. 

 

아까 생성한 xib 파일을 클릭해서 다음과 같은 화면에서 오른쪽의 설정화면에서 Custom Class를 적용할 것입니다.

이렇게 다음과 같이 방금 생성한 Custom Class를 File Owner에 적용해주세요.

여기서 다음에 사용할 방법과 가장 큰 차이가 생깁니다. 

이제 xib에 있는 뷰를 클릭하면 오른쪽에 코드와 함께 볼 수 있게 활성화가 되었을 것입니다.

여기서 initializer 두 가지를 구현해주시면 됩니다.

class CustomView: UIView {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
}

 

우선은 여기까지만 작성해주시고 두 initializer의 차이는 Interface Builder로 불러올 때와 코드로 생성할 때, 각각 불린다는 차이가 있습니다.

필요할 때, 두 가지의 initializer 각각 구현해주시면 됩니다.

 

그리고 추가 작업이 필요합니다.

저희는 지금 File Owner에 지정했기 때문에, 현재 xib를 뷰로 불러오지 않은 상태입니다.

 

이제 loadXib()라는 메소드를 구현해서 커스텀 클래스를 불러오고 현재 CustomView에 addSubview를 실행해줍니다.

class CustomView: UIView {
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.loadXib()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.loadXib()
    }
    
    private func loadXib() {
        let identifier = String(describing: type(of: self))
        let nibs = Bundle.main.loadNibNamed(identifier, owner: self, options: nil)
        
        guard let customView = nibs?.first as? UIView else { return }
        customView.frame = self.bounds
        self.addSubview(customView)
    }
}

근데 여기서 이상한 점이 있죠..?

왜 나는 불러오면 그걸로 끝일 줄 알았는데 위에 View가 하나 더 생기지..?

 

바로 File OwnerCustom Class를 지정했기 때문입니다. 잘 보면 loadNibNamed를 해올 때, first로 들고오는 것을 알 수 있는데, 밑의 그림처럼 File Owner에는 여러개의 뷰가 들어갈 수 있기 때문에 이 중에서 저희가 Interface Builder로 커스텀 한 클래스를 가져와서 현재 View에 계층을 한 단계 더 쌓은 구조입니다!!

아마 여기까지 구현한 상태에서 UIView를 생성한 상태에서 Custom Class를 지정해서 호출하면 여러분이 커스텀한 View가 화면에 짜잔하고 나오는 것을 확인하실 수 있습니다.

여기까지가 File Owner를 이용한 UIView Custom하는 방법이었습니다.

 

다음으로는 UIView에 Custom Class를 적용해서 생성하는 방법을 알아보겠습니다.

 

 

UIView Custom Class

가장 처음 세팅한 상태에서 File Owner에 Custom Class를 적용해주는 방법이 아닌 UIView에 직접 지정을 해줄 것입니다.

이렇게 밑에 있는 View에게 적용하길 원하는 Custom View의 이름을 지정해주세요.

그리고 이번에는 호출할 때, 호출하길 원하는 곳에서 다음과 같은 코드를 입력해줍니다.

let identifier = String(describing: CustomView.self)
let nibs = Bundle.main.loadNibNamed(identifier, owner: self, options: nil)

guard let customView = nibs?.first as? CustomView else { return }

이렇게하면 원하는 Xib로 커스텀 한 View를 불러와서 사용해줄 수 있습니다.

 

여기서 차이가 보이시나요?? 

first의 요소를 캐스팅할 때, 바로 원하는 CustomView로 캐스팅해서 사용하고 있습니다.

 

조금만 생각해보면 당연하게 first를 Custom Class로 지정했기 때문이겠죠!!

이렇게 2가지의 방법을 살펴보았습니다.

 

어떤 방법이 어떻게 더 좋은지 차이가 느껴지시나요?

 

 

두 방법 모두 장단점이 있는 것 같습니다.

File Owner의 Custom Class를 지정한 경우에는 뭔가 뷰의 구조가 하나 더 위로 생기는 것 같아서 이상하죠..?

하지만 Custom View를 호출할 때, 바로 해당 인스턴스의 이니셜라이져로 호출할 수 있다는 장점이 있습니다.

let customView = CustomView(frame: .zero)

 

반면에 View를 Custom Class로 지정한 경우에는 저렇게는 호출이 불가능하지만 해당 뷰를 바로 호출할 수 있기 때문에, 뷰의 계층구조가 하나 더 쌓이지 않아서 조금 더 직관적일 수 있겠죠.

만약 이 방법을 활용한다고 하면 UIView의 Extension을 구현해서하면 좀 더 효율적으로 활용할 수 있을 것 같습니다.

extension UIView {
    static func loadFromNib<T>() -> T? {
        let identifier = String(describing: T.self)
        let view = Bundle.main.loadNibNamed(identifier, owner: self, options: nil)?.first
        return view as? T
    }
}

let customView: CustomView? = UIView.loadFromNib()

이런식으로 구현해서 사용하면 타입만 지정해서 원하는 CustomView를 바로바로 호출할 수 있습니다.

 

 

이렇게 두 가지의 방법 중에서 더 편하다고 생각하고 프로젝트에 맞는 방법을 각자 사용하면 될 것 같습니다.

도움이 되었으면 좋겠습니다 :)

 

반응형