본문 바로가기
iOS

[iOS/Swift] SnapKit 라이브러리 공식문서 같이 읽어보기

by 코코종 2021. 12. 17.

안녕하세오 코종입니다! 

제가 너무 늦게왔죠...?? ㅋㅋㅋㅋㅋㅋㅋㅋ

 

변명 및 반성문...

11월 초에 블로그를 만들어놓고 '조금 공부를 한 다음에 지나갔던 개념 블로그에 적으면서 복습해야지' 했는데요...

그게말이죠 하하.. 제가 지금 SeSAC iOS 과정을 듣고 있는데요 7주차 까지는 '뭐 과제 하면서 할만하네! 블로그도 써야지' 했는데요

8주차에 '아이폰 기본 메모앱 만들기'를 1주일짜리 프로젝트? 과제?로 했는데 생각보다 너어어무 할게 많더라구요 ㅜㅜ 그래서 미뤘습니다

근데 9주차부터는 '개인앱 출시'프로젝트지 뭡니까..? 그래서 정신을 잃었습니다 ^^ 1달이 어떻게 지나가버렸는지 모르겠네요

시간이 정신없이 지나가벌임..

암튼! SnapKit을 알아보자

기존에 스토리보드로 작업하던 것을 코드로 작성하는 법을 배웠는데요. 이게 또 만만치 않습니다(생각한대로 한다고 했는데 오토레이아웃이 고장나요...) 그래도 이런 불편함을 해결하고자 라이브러리가 있는거 아니겠습니까?

 

먼저 할 일

먼저 코드로 UI를 구성하기 위해서는 스토리 보드를 지워줘야겠죠? 근데 그런다고 끝이 아니랍니다

까먹지 않게 3단계로 정리했어요

1. Main 스토리보드 지우기(reference만 지우는게 아니라 trash 해버려야해요)

2. Targets 에서 Main Interface 지우기

3. info.plist 에서 Storyboard Name 지우기

(이제 진짜 안까먹겠지...?)

 

그리고 당연히 Snapkit을 깔아줘야겠죠? SPM과 CocoaPod 등으로 설치가 가능한데 그건 공식 문서에 다 있으니까 따라하시면 됩니다(귀찮아서 그런거 아닙니다 최소한의 공식문서를 보게 하기 위함입니다 암튼 그럼)

 

entry point를 잡기

스토리 보드를 지워버렸으니 뭐부터 시작해야할지 앱이 모르잖아요?(3단계로 싹 지워버렸으니까요)

그래서 우리는 어떤 swift(ViewController)를 시작점으로 할 지 알려줘야합니다

이건 iOS13에서 새로 도입된 SceneDelegate에서 처리해준답니다! 카톡도 최소 지원버전이 13이니까 12이하는 좀 구시대의 유물이 되어버린거 같네요(대충 이제 13은 필수가 아닐까 하는 말)

SceneDelegate에 제일 처음에 있는 willConnectTo에 아래와 같이 코드를 작성해줍시다

 

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

     guard let windowScene = (scene as? UIWindowScene) else { return }
     self.window = UIWindow(windowScene: windowScene)
     let vc = ViewController() // 시작할 VC를 넣어주면 됩니다 저는 ViewController에 코드를 작성하려구요
     window?.rootViewController = vc
     window?.makeKeyAndVisible()
     
 }

 

참고로 makeKeyAndVisible의 공식 설명은 아래와 같이 되어있습니다.

This is a convenience method to show the current window and position it in front of all other windows at the same level or lower. If you only want to show the window, change its isHidden property to false.

 

간단하게 설명하면 keyWindow로 지정해주고(앞서 rootViewController로 설정해준 것을) 다른 윈도우보다 앞에 보이게 해준다는 내용이다. 또한 단순히 보여주기만 하는것은 isHidden을 false로 바꾸면 된다는 내용이다.

 

SnapKit 없이 오토레이아웃 잡기

일단 가장 기본적인 방법대로 오토레이아웃을 잡아볼까요? 원래 귀찮은걸 간단하게 만든 것은 귀찮은걸 먼저 해봐야 체감이 확 옵니다 :)

class ViewController: UIViewController {

    let redView = UIView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        
        setRedView()
    }
    
    func setRedView() {
        redView.backgroundColor = .red
        view.addSubview(redView)
        redView.translatesAutoresizingMaskIntoConstraints = false
        
        // top = superView.top + 100
        let topConstraint = NSLayoutConstraint(item: redView, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .top, multiplier: 1, constant: 100)
        // leading = superView.leading
        let leadingConstraint = NSLayoutConstraint(item: redView, attribute: .leading, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .leading, multiplier: 1, constant: 100)
        // width = 100
        let widthConstraint = NSLayoutConstraint(item: redView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 0.5, constant: 100)
        // height = 200
        let heightConstraint = NSLayoutConstraint(item: redView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 200)
        
        view.addConstraints([topConstraint, leadingConstraint, widthConstraint, heightConstraint])
        // 또는 topConstraint.isActive = true
        // 또는 view.addConstraint(topConstraint)
        
    }
    
}

주석에 설명은 달아둔 것 처럼 나왔네요

SnapKit 사용해서 오토레이아웃 잡아보기

자 그럼 이 지저분스한 코드가 어떻게 간단하게 바뀌는지 볼까요?

import UIKit
import SnapKit

class ViewController: UIViewController {

    let redView = UIView()
    let blueView = UIView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        
        setRedView()
        setBlueView()
    }
    
    func setRedView() {
        redView.backgroundColor = .red
        view.addSubview(redView)
        redView.translatesAutoresizingMaskIntoConstraints = false
        
        // top = superView.top + 100
        let topConstraint = NSLayoutConstraint(item: redView, attribute: .top, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .top, multiplier: 1, constant: 100)
        // leading = superView.leading
        let leadingConstraint = NSLayoutConstraint(item: redView, attribute: .leading, relatedBy: .equal, toItem: view.safeAreaLayoutGuide, attribute: .leading, multiplier: 1, constant: 100)
        // width = 100
        let widthConstraint = NSLayoutConstraint(item: redView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 0.5, constant: 100)
        // height = 200
        let heightConstraint = NSLayoutConstraint(item: redView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: 200)
        
        view.addConstraints([topConstraint, leadingConstraint, widthConstraint, heightConstraint])
        // 또는 topConstraint.isActive = true
        // 또는 view.addConstraint(topConstraint)
        
    }
    
    func setBlueView() {
        blueView.backgroundColor = .blue
        view.addSubview(blueView)
        
        // blueView.translatesAutoresizingMaskIntoConstraints = false 는 스냅킷이 알아서 해준답니다!!
        
        blueView.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(100)
            make.trailing.equalTo(view.safeAreaLayoutGuide).offset(-100)
            make.width.equalTo(100)
            make.height.equalTo(200)
        }
        
    }
    
}

스냅킷은 전설이다...

확실히 귀찮은 방법을 거치고 쉬운 방법으로 해보니까 말도 안된다고 느끼네요( translatesAutoresizingMaskIntoConstraints를 안써도 되는거도 너무 좋네요 무진장 길어서 신경쓰였는데)

 

공식문서 같이 읽기

제가 암만 예시들어봤자 공식문서에는 기능이 더 많다구욧!! 같이 보시죠!

SnapKit을 쓰면 위에 예시로 들었던 것 처럼 NSLayoutConstraint를 노가다로 안써도 됩니다.

 

그리고 constant값은 offset과 inset으로 대체 되어서 더 직관적으로 값을 알 수 있습니다

- offset은 constant와 같지만 부호가 중요합니다! 제가 이해하기로는 좌표처럼 사용이 되는것 처럼 이해했어요. trailing이나 bottom은 좌표상으로 음수방향으로 간격을 주잖아요? 그래서 blueView에서도 trailing의 offset을 -100으로 준겁니다

- inset은 기존에 저희가 스토리보드로 연결할 때 보면 constant를 그냥 양수로 줬었죠? 그거랑 똑같이 trailing이나 bottom에도 그냥 양수로 적는 방식입니다. 물론 음수를 적으면 반대로 갑니다. 방향에 따라서 음수를 쓰는게 헷갈린다면 써보셔요

 

그래서 저는 inset은 edges 처럼 4가지 제약을 똑같이 걸거나 top - bottom, leading - trailing 처럼 짝으로 이뤄진 제약을 걸 때 사용한답니다!

 

저희 맨날 anchor 연결하고 인스펙터 영역에서 =, <=, >= 이런거 들어가서 설정하셨죠? 스냅킷에서는 간단하게 된다구요!

 

뭐가 뭔지 나와있네요 슥~ 읽어 보면 똑같은거죠?
앞서 말한 &gt;= 같은 처리를 간단하게 할 수 있습니다

두가지 속성을 줘서 범위를 정할수도 있고, make.left 등에 값만 적으면 알아서 superview의 left라고 인식해준답니다.(개인적으로 이게 너무 똑똑한거 같아요) 또 CGSize나 UIEdgeInsets 같은 요소들도 사용이 가능합니다

 

오토레이아웃에서 빠질수 없는(충돌이 나니까 빠질수없음ㅋㅋㅋ) 우선순위도 Int값이나 간단한 문구로 사용이 가능합니다

 

composition은 '구성' 이라는 뜻인데 왜 이런 제목을 썼을까요..?

edges는 4방향(top, left, bottom, right)를 한번에 처리할 때 사용합니다. inset을 같이 사용하면 편리하겠네요

size는 너비와 높이를 한번에 처리할 때 사용합니다(정사각형으로 많이 쓰잖아요?)

center는 가운데 정렬(가로, 세로 모두)을 한번에 처리할 때 사용합니다

그리고 밑에 chain해서 사용할 수 있다고 하는데 이건 말 그대로 여러 속성을 한번에 처리가 가능하다는 말입니다. 4방향이나 짝으로 이루어진 속성 말고 top과 left만 똑같이 하고 싶다면 make.top.left.equalTo() 를 쓰면 된다네요! (와 진짜 사용성 오져따리)

 

한 번 선언한 constraint를 잠깐 비활성화 할 수 있습니다! 막 UI를 짜다보면 이렇게도 했다가 저렇게도 했다가 바꿔보잖아요? 근데 스토리보드로 하면 지웠다가 다시 연결해야하는 번거로움이 너어어어어무 불편했는데(ctr + z도 한계가 있잖아요?) 잠시 제약조건을 비활성화 시켜놓고 다른 제약을 걸 수 있답니다

또, offset이나 inset을 업데이트 할 수 있답니다(굳이 저~ 위로 올라가서 값을 바꾸지 않아도 된다는 말이죠)

 

앞에서 offset 과 inset을 업데이트 한 것 처럼 다른 제약 조건의 constant 값도 updateConstraints를 이용해서 덮어 쓸 수 있습니다(원래는 덮어쓰면 conflict 나면서 '빼애애액!! 충돌!!!!' 하잖아요 그걸 쉽게 처리할 수 있는거죠)

그리고 애플에서는 이런 방식의 사용을 권장한다네요?

 

remark는 말그대로 다시 지정하는것인데 update는 값만 바꿔줄 수 있다면 remark는 다시 찍는거라서 기존에 있던 제약 조건을 삭제하고  어디에 연결할지도 설정하고 다시 연결합니다(원래는 equalTo(label) 이었던 것을 equalTo(button) 으로 바꿀 수 있다는 거죠)

 

당연히 safeArea에 대한 처리가 존재한다

top과 bottom의 경우 safeArea에 대한 처리가 꼭!!! 필요하기 때문에 지원을 해준다.(여담이지만 leading, trailing이라고 safeArea가 안불려지지 않는다 다만 똑같을 뿐)

 

이 기능도 당장은 써보지 않았지만 내가 생각한대로 레이아웃이 잡히지 않는다면 디버그를 통해서 쉽게 판별이 가능할 것 같다. (솔직히 디버그 창에서 나오는 이름은 봐도 알 수가 없기 때문에...ㅎ)

 

끝 마치며

얼렁뚱땅 어찌저찌 공식 문서의 내용을 같이 살펴봤다. 아직 iOS 삐약이기 때문에 부족한 부분이 많고 실제로 사용해보지 못했던 기능도 많지만 읽으면서 다른 분들의 글도 찾아보고 정리하니까 도움이 많이 된 것 같다(대신에 시간은 순삭..!)

배웠던 개념중에 그나마 좀 익숙해진 개념(UITableView 라던가)에 대해 차차 글을 작성하고자 한다 호홓

다시 꾸준히 글을 쓰는 코코종이 되겠습니다~