[iOS] xib 사용해보기 (feat.체크박스)

Yujin·2021년 11월 7일
0

iOS

목록 보기
3/5
post-thumbnail

말로만 듣던 xib 한번 써봐야겠다 생각하고 있었는데 세미나 과제에 체크박스 구현이 있어서 ! 한번 써보았다.

💡xib를 알아야 하는 이유

iOS의 UI를 구성하는데에는 대표적으로 세가지 방법이 있다고 한다.

  1. Storyboard
  2. xib
  3. code

세 가지의 장단점은 대략 요렇다구 한다 !

Storyboardxibcode
장점구현하기가 쉽고, 빠르게 프로토타입을 만들 수 있다.

네비게이션의 흐름을 쉽게 파악 할 수 있다.

Static Cell을 이용 할 수 있다.
storyboard에 비해 조금 더 구체적인 UI 구현이 가능하다.

merge 충돌이 storyboard에 비해 적다.

여러 클래스에서 하나의 UI를 공유해서 사용 할 경우 좋다.
코드로 한줄 한줄 있어서 어떤 기능인지 직관적이다.

읽기 쉽고 유지보수가 간편하다.

많은 제어와 이해를 통해 다양하게 구현이 가능하다.merge 충돌 해결을 하기 쉽다.
단점여러 사람이 작업 할 경우 merge 충돌이 일어날 수 있다.

재사용을 하고자 할 때 뷰 컨트롤러 자체를 함께 복사해야함으로 재사용성이 낮다.
성능이 느리다.다른 사람이 개발했던 코드일 경우 리팩토링이 복잡하다.

아무쪼록 스토리보드와 코드의 장점을 적절하게 가져와서 편리하게 재사용하려면 xib 쓰는 법을 알아야 할 듯 하다.



💡xib, nib, Storyboard 어떻게 다른가

그런데 일단 xib,nib,,,어려운이름...무엇이 다른지, 뭐가 뭔지 모르겠어서 조사하던 중 아주 이해가 잘 되는 정리가 잘 된 글을 발견 ! (출처)

XIB,NIB, Storyboard 어디에 사용되나요?

  • XIB, NIB, Storyboard는 파일형태로 되어있고, 화면을 구성할때 사용됩니다

    MVC 디자인 패턴을 위해 뷰 코드와 컨트롤러를 분리하는 목적으로 만들어진 파일 입니다

NIB 파일은 무엇인가요?

  • Nextstep Interface Builder의 약자로, 화면을 구성하는 클래스들을 바이너리 형태의 압축 파일로 저장하고 있습니다

바이너리로 이뤄져있는 NIB파일 내부를 바라본 모습 🔽

XIB 파일은 무엇인가요?

  • Xcode Interface Builder의 약자로, 화면을 구성하는 클래스들을 XML문법에 맞춰 저장되고 있습니다.

XIB파일은 왜 생기게 되었나요?

  • 바이너리로 저장하지 않고 XML 형태로 저장하기 때문에 수정된 부분을 알 수 있어서 파일 관리가 아닌 소스코드로 관리가 가능해졌습니다.

XML형태의 XIB파일을 변경 후 비교해본 모습 🔽

  • 직접 수정하려면 XML문법을 맞춰서 수정해야되기 때문에 번거로울 수 있지만, Xcode에선 Interface Builder를 제공하여 XML 형태가 아닌 그래픽 형태로 수정할 수 있게 도와줍니다.

XIB파일을 Xcode의 Interface Builder로 본 모습 🔽

프로그램이 뷰 정보를 읽어들이는 방법

  • 뷰 정보를 담고 있는 XIB파일을 빌드하게 되면, 접근하기 쉬운 바이너리 NIB파일로 컴파일 되고, 앱의 번들(앱 실행에 사용되는 파일이 저장된 폴더)로 복사된 후 실행파일에서 사용됩니다.

XIB를 컴파일하면 NIB가 만들어집니다 🔽

XIB파일이 빌드과정후 생성된 app 패키지안에 NIB파일로 저장된 모습 🔼

그렇다면 Storyboard는 무엇인가요?

  • 스토리 보드는 뷰 정보와 뷰와 뷰 사이의 관계에 대한 정보를 가지고 있는 파일 입니다. 그렇기 때문에 뷰 정보인 XIB의 내용과 뷰 관계정보를 포함하고 있어서 XML로 이뤄져 있습니다. 빌드를 하게 되면 컴파일된 storyboard파일로 .storyboardc라는 파일이 생성됩니다.

  • .storyboardc 파일은 패키지 파일로 되어있고 이 내부는 nib파일과 nib파일을 관리하는 plist파일이 존재합니다.

.storyboardc파일의 패키지 내부 모습 🔼

Storyboard파일 내부 구조 🔼

이렇게 xib는 뷰를 나타낸 xml파일이고 nib는 xib를 컴파일하면 생성되는 바이너리 파일이라는 것으로 정리가 되었고 ! 이제 본격적으로 xib파일로 커스텀뷰를 만들어보자.



💡xib로 본격적으로 CheckBox 만들어보기

1. xib, swift 파일 만들기

아래 사진처럼 checkbox를 구현하기 위해 CheckBoxView.xib와 CheckBoxView.swift를 만들어 주겠습니다.

CheckBoxView.xib 만들기

xib파일을 만들 때는 사진처럼 User Interface의 View를 선택하여 만들어 줍니다!

CheckBoxView.swift 만들기

그 다음으로는 뷰를 관리하기 위해 UIView를 상속받는 클래스를 만들어줍니다.

2. xib 파일의 File's Owner의 Class 설정

.xib, .swift 파일을 생성했으니 이제 두 파일을 연결할 차례입니다.

두 파일을 연결해주면 UILabel이나 UIButton과 같이 UIView를 상속하는 나만의 CustomView로 사용할 수 있습니다.


.xib 파일을 열고 Placeholders 아래에 있는 File's Owner를 클릭하고 Attributes Inspector 탭에 File's Owner의 Class를 지정하는 곳이 있는데 여기에 CustomView를 입력해주면 화면과 소스가 연결 됩니다.

아래는 용어 설명 참고,,,

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로 지칭
(Responder Chain 공부 필요..)

3. 뷰 그리기

View의 size와 AutoLayout 설정

우리가 만들어준 view의 size를 Freeform으로 설정하여 화면의 크기를 자유자재로 바꿀 수 있게 해줍니다.
safe area를 체크해제 안하면 auto layout에서 버그가 생기는 경우가 존재하므로 채크해제를 해줍니다.


정사각형의 뷰를 만들 것이기 때문에 width와 height를 1:1 비율로 설정해 줍니다.

UIView와 UILabel 추가해주기

버튼 테두리를 위한 UIView를 추가하고 그 안에 Text가 ✓인 UILabel을 추가하고 Constraints를 지정해줍니다.

4. CustomView 초기화

5. checkBoxView 클래스 초기화

checkBoxView는 우리가 만들어준 View이기 때문에 직접 초기화를 해줘야 합니다.

일단 아까 만들어준 view를 모두 @IBOutlet 해줍니다.
checkBoxView는 xib 루트 뷰이고
나머지 둘은 우리가 추가해 준 UI object들입니다.

여기서 초기화를 위한 함수로 commonInit()이라는 함수를 만들고
override init(frame:)required init?(coder:)에 각각 넣어줬는데

전자는 코드로 초기화 할 때 필요한 함수이고 후자는 스토리보드로 초기화 할때 필요한 함수라고 합니다. (둘의 차이는 더 공부를 해봐야 할 듯)

override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonInit()
    }
    
    private func commonInit(){
        
        let bundle = Bundle(for: CheckBoxView.self)
        //nib 파일을 이름으로 찾아서 메모리에 로드하여, nib파일 내의 top-level 객체들을 [Any]? 타입으로 반환
        bundle.loadNibNamed("CheckBoxView", owner: self, options: nil)
        addSubview(checkBoxView)
        
        //초기 UI상태 설정 (비어있는 회색테두리의 체크박스)
        checkBoxUIView.layer.borderColor = UIColor.gray.cgColor
        checkBoxUIView.layer.borderWidth = 1.0
        checkBoxUIView.layer.cornerRadius = 5
        checkLabel.isHidden = true
         
        
        //self(checkBoxview)와 눌렀을 때 실행할 함수checkBoxClicked()를 인자로 넣어 생성한 
        //UITapGestureRecognizer을 추가해준다.
        self.checkBoxView.addGestureRecognizer(UITapGestureRecognizer(target: self,action: #selector(self.checkBoxClicked(_:)))) 
        //만들어준 뷰가 제스처를 인식 할 수 있도록 설정
        self.checkBoxView.isUserInteractionEnabled = true
        
    }

7. CheckBoxView.swift 코드

checkBox를 눌렀을 때 실행될 checkBoxHighLight() 함수는 delegate로 만들어 viewcontroller에서 구현 되도록 할 것이다.
따라서 CheckBoxDelegate프로토콜을 만들어 checkBoxHighLight()를 선언해 놓는다. CheckBoxViewDelegate.swift 파일을 따로 만들어 넣어줘도 되지만 귀찮아서 그냥 CheckBoxView.swift 맨위에 넣어주었다.

protocol CheckBoxDelegate: class {
    func checkBoxHighlight(cb: CheckBoxView)
}

CheckBoxView class 안에 delegate 변수를 추가한다

var delegate: CheckBoxDelegate?

checkBoxClicked() 함수

제스처가 생겼을 때 호출 될 함수 안에 델리게이트 함수를 넣어준다.

@objc func checkBoxClicked(_ sender: Any) {
            // CheckBoxDelegate 함수 호출
            delegate?.checkBoxHighlight(cb: self)
        }

8. Main.storyboard에 뷰 추가

UIView를 추가해주고 Class 이름을 CheckBoxView로 지정해줍니다.

9. ViewController 코드

delegate를 지정해주고 checkBoxHighlight()를 구현합니다.


import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var checkBoxView: CheckBoxView!
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //delegate지정
        self.checkBoxView.delegate = self
    }


}

//delegate 함수 구현
extension ViewController: CheckBoxDelegate{
    
    func checkBoxHighlight(cb: CheckBoxView) {
        //비밀번호 표시 체크 해제 할때
        if cb.checkLabel.isHidden == false {
            cb.checkLabel.isHidden = true
            cb.checkBoxUIView.layer.borderColor = UIColor.gray.cgColor
            cb.checkBoxUIView.layer.borderWidth = 1
            cb.checkBoxUIView.backgroundColor = UIColor.white
            
            
        } else{// 비밀번호 표시 체크 할 때
            cb.checkLabel.isHidden = false
            cb.checkLabel.textColor = UIColor.white
            cb.checkBoxUIView.layer.borderWidth = 0
            cb.checkBoxUIView.layer.cornerRadius = 5
            cb.checkBoxUIView.backgroundColor = UIColor(red: 66/255, green: 133/255, blue: 244/255, alpha: 1)
        
        }
    }
}
profile
하나하나 알아가는 하루하루

0개의 댓글