๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
iOS

[iOS] SnapKit๊ณผ Then ์‚ฌ์šฉํ•˜๊ธฐ

by lizzydev 2023. 3. 29.

iOS์—์„œ ์ฝ”๋“œ๋กœ ๋ทฐ ์งค ๋•Œ ์ƒ์‚ฐ์„ฑ์„ ํฌ๊ฒŒ ๋†’์—ฌ ์ฃผ์–ด ๋งŽ์ด ์“ฐ์ด๊ณ  ์žˆ๋Š” SnapKit๊ณผ Then ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿ“• SnapKit

SnapKit๋Š” iOS์™€ OS X ๋ชจ๋‘์—์„œ ์˜คํ†  ๋ ˆ์ด์•„์›ƒ์„ ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•œ DSL์ž…๋‹ˆ๋‹ค.

DSL: ํŠน์ •ํ•œ ๋„๋ฉ”์ธ์— ํŠนํ™”๋œ ์–ธ์–ด.

Requirements

  • iOS 10.0+ / Mac OS X 10.12+ / tvOS 10.0+
  • Xcode 10.0+
  • Swift 4.0+

SnapKit ์‚ฌ์šฉ๋ฒ•

SnapKit ์‚ฌ์šฉํ•˜๊ธฐ ์ „

labelTimer.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
  lblTimer.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.45),
  lblTimer.heightAnchor.constraint(equalToConstant: 45),
  lblTimer.topAnchor.constraint(equalTo: viewProgress.bottomAnchor, constant: 32),
  lblTimer.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])

์‚ฌ์šฉํ•˜๊ธฐ ์ „ ์ฝ”๋“œ๋Š” translatesAutoresizingMaskIntoConstraints ๋ฅผ false๋กœ ๋ฐ”๊ฟ”์ฃผ๊ณ  ์ถ”๊ฐ€ํ•  Anchor๋“ค์„ ์ผ์ผ์ด ๋‹ค activate ํ•ด์ฃผ๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

SnapKit ์‚ฌ์šฉ ํ›„

labelTimer.snp.makeConstraints {
  $0.width.equalToSuperview().multipliedBy(0.45) // 1
  $0.height.equalTo(45) // 2
  $0.top.equalTo(viewProgress.snp.bottom).offset(32) // 3
  $0.centerX.equalToSuperview() // 4
}

snapkit์„ ์“ฐ๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ translatesAutoresizingMaskIntoConstraints ๋ฅผ false๋กœ ๋ฐ”๊ฟ”์ฃผ๊ณ  activate๋ฅผ ํ•ด์ค๋‹ˆ๋‹ค.

ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ข€ ๋” ์ง๊ด€์ ์ด๊ณ  ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์†Œ๋“œ๋“ค ์ด๋ฆ„์ด๋‚˜ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•๋“ค์ด ๊ธฐ์กด๋ณด๋‹ค ๋” ๊ฐ„๋‹จํ•ด์ง„ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

์ฒด์ธ ํ˜•ํƒœ๋กœ ๋”์šฑ ๊ฐ„ํŽธํ•˜๊ฒŒ ์˜คํ† ๋ ˆ์ด์•„์›ƒ ์žก๊ธฐ

์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š”

child.snp.makeConstraints { 
  $0.leading.equalToSuperview()
  $0.top.equalToSuperview()
  $0.trailing.equalToSuperview()
  $0.bottom.equalToSuperview()
}

์•„๋ž˜์™€ ๊ฐ™์ด ํ”„๋กœํผํ‹ฐ๋“ค์„ ์ฒด์ธํ˜•ํƒœ๋กœ ์—ฐ๋‹ฌ์•„ ์ž‘์„ฑํ•œ ํ›„ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ฝ”๋“œ ์–‘์„ ํ›จ์”ฌ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

child.snp.makeConstraints { make in
  make.leading.top.trailing.bottom.equalToSuperview()
}

๋” ์ถ”๊ฐ€์ ์ธ ๋‚ด์šฉ์€ ์•„๋ž˜ SnapKit github์™€ Kodeco ๊ฐ•์˜์—์„œ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/SnapKit/SnapKit

SnapKit for iOS: Constraints in a Snap

๐Ÿ“˜ Then

Then์€ ์Šคํƒ€์ผ์‰์–ด์˜ iOS ๊ฐœ๋ฐœ์ž ์ „์ˆ˜์—ด๋‹˜์ด ๋งŒ๋“  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž…๋‹ˆ๋‹ค.

์•ž์„  Snapkit์€ ์ƒ์„ฑ๋œ ui์˜ ์˜คํ† ๋ ˆ์ด์•„์›ƒ์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ํ•  ๋•Œ ์“ฐ์ธ๋‹ค๋ฉด Then์€ ui ์ธ์Šคํ„ด์Šค๋ฅผ ์ฒ˜์Œ ์ƒ์„ฑํ•  ๋•Œ ์“ฐ์ž…๋‹ˆ๋‹ค. ํด๋กœ์ €๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ข€ ๋” ์ง๊ด€์ ์ด๊ณ  ๊น”๋”ํ•˜๊ฒŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋งŽ์ด ์“ฐ์ž…๋‹ˆ๋‹ค.

Then ์‚ฌ์šฉํ•˜๊ธฐ ์ „ ์ฝ”๋“œ

let label: UILabel = {
  let label = UILabel()
  label.textAlignment = .center
  label.textColor = .black
  label.text = "Hello, World!"
  return label
}()

Then์„ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ

let label = UILabel().then {
  $0.textAlignment = .center
  $0.textColor = .black
  $0.text = "Hello, World!"
}

ํ™”๋ฉด์— ์˜ฌ๋ฆด UI์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ”„๋กœํผํ‹ฐ๋“ค์„ ์„ค์ •ํ•  ๋•Œ ์ฝ”๋“œ ์–‘์ด ์ค„์–ด๋“ค๊ณ  ์ง๊ด€์ ์ด๊ณ  ๊น”๋”ํ•œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋” ์ƒ์„ธํ•œ ๋‚ด์šฉ์€ ํ•˜๋‹จ์˜ ๋ ˆํฌ์ง€ํ„ฐ๋ฆฌ์—์„œ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://github.com/devxoul/Then

CocoaPod ์„ ์ด์šฉํ•˜์—ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ํ•˜๊ธฐ

๊ทธ๋Ÿผ ์ด์ œ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

1. CocoaPod์ด ์—†๋‹ค๋ฉด ๋จผ์ € ํ„ฐ๋ฏธ๋„์—์„œ ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋กœ CocoaPod์„ ์„ค์น˜ํ•ด์ค๋‹ˆ๋‹ค.

gem install cocoapods

CocoaPods : Swift ๋ฐ Objective-C ์ฝ”์ฝ”์•„ ํ”„๋กœ์ ํŠธ์˜ ์ข…์†์„ฑ ๊ด€๋ฆฌ์ž. 96,000๊ฐœ ์ด์ƒ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ณด์œ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ 3๋ฐฑ๋งŒ ๊ฐœ ์ด์ƒ์˜ ์•ฑ์—์„œ ์‚ฌ์šฉ.

 

2. Snapkit์„ ์‚ฌ์šฉ ํ•  ํ”„๋กœ์ ํŠธ .xcodeproj๊ฐ€ ์žˆ๋Š” ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•˜์—ฌ ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

pod init //Podfile ์ƒ์„ฑ vim Podfile. //Podfile ํŽธ์ง‘

 

3. Podfile์— ํ•˜๋‹จ์˜ ์ฝ”๋“œ ๋Œ€๋กœ snapkit๊ณผ then์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ( i ๋ˆŒ๋Ÿฌ์„œ ํŽธ์ง‘ ๋ชจ๋“œ๋กœ ์ „ํ™˜ ํ›„ ํ…์ŠคํŠธ ์ถ”๊ฐ€)

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'WorldHunter' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for WorldHunter
  pod 'SnapKit', '~> 5.6.0'
  pod 'Then'
end

4. Podfile ์ €์žฅ ํ•œ ํ›„ pod install (์ €์žฅ : esc ๋ˆŒ๋Ÿฌ์„œ ํŽธ์ง‘๋ชจ๋“œ ์ข…๋ฃŒ ํ›„ :wq ์ž…๋ ฅ)

๊ธฐ์กด ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ซ๊ณ  ๋‚˜๊ฐ€๋ฉด ์ƒˆ๋กœ ์ƒ๊ธด xcworkspaceํŒŒ์ผ์ด ์žˆ๋Š”๋ฐ ์•ž์œผ๋กœ๋Š” ์ด ํŒŒ์ผ์„ ์—ด์–ด์„œ ์ž‘์—…์„ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

xcworkspace๋ž€?

  • workspace๋Š” ํ”„๋กœ์ ํŠธ ๋ฐ ๊ธฐํƒ€ ๋ฌธ์„œ๋ฅผ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ ํ•จ๊ป˜ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” Xcode document์ž…๋‹ˆ๋‹ค
  • workspace ์— ์›ํ•˜๋Š” ์ˆ˜์˜ Xcode ํ”„๋กœ์ ํŠธ ๋ฐ ๋‹ค๋ฅธ ํŒŒ์ผ๋“ค์„ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • ๊ฐ Xcode ํ”„๋กœ์ ํŠธ์˜ ํŒŒ์ผ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ ์™ธ์—๋„ workspace๋Š” ํฌํ•จ๋œ ํ”„๋กœ์ ํŠธ์™€ target ๊ฐ„์˜ ์•”์‹œ์ (implicit) ๋ฐ ๋ช…์‹œ์ (explicit) ๊ด€๊ณ„๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์™ธ๋ถ€๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ ์—†์ด ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋Š” xcodeproj๋กœ ์‹คํ–‰ํ•ด๋„ ๋˜์ง€๋งŒ, ์™ธ๋ถ€๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๊ฒฝ์šฐ์—๋Š” ๋‘˜ ์ด์ƒ์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ชจ์•„ ํ•œ ๊ตฐ๋ฐ์„œ ์ž‘์—…ํ•˜๋Š” ์ƒํ™ฉ์ด ๋˜๋‹ˆ workspace ์—์„œ ์ž‘์—…์„ ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

xcworkspace๋ฅผ ์—ด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด SnapKit๊ณผ Then์ด ์ถ”๊ฐ€ ๋œ ๊ฒƒ์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์›ํ•˜๋Š” ํŒŒ์ผ์—์„œ import๋ฅผ ํ•ด์ค€ ๋’ค ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Example

import UIKit
import SnapKit
import Then

class ViewController: UIViewController {
    //MARK: Components
    
    private let titleView = UIView()
		//Then ์‚ฌ์šฉํ•ด์„œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
    private let titleLabel = UILabel().then{
        $0.text = "์•ฝ์† ์‹ ์ฒญ"
        $0.font = UIFont.hanSansBoldFont(ofSize: 18)
    }
    private let closeButton = UIButton().then{
        $0.setBackgroundImage(UIImage(named: "btn_close"), for: .normal)
        $0.addTarget(self, action: #selector(touchUpCloseButton(_:)), for: .touchUpInside)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        setLayout()
    }

   //MARK: Layout
    func setLayout() {
        self.navigationController?.isNavigationBarHidden = true
        view.addSubview(titleView)
        titleView.addSubviews([titleLabel,closeButton])
        
        titleView.snp.makeConstraints{
            $0.top.leading.trailing.equalTo(view.safeAreaLayoutGuide)
            $0.height.equalTo(58)
        }
        titleLabel.snp.makeConstraints{
            $0.centerX.equalToSuperview()
            $0.centerY.equalToSuperview()
        }
        closeButton.snp.makeConstraints{
            $0.trailing.equalToSuperview().offset(-4)
            $0.centerY.equalToSuperview()
            $0.width.height.equalTo(48)
        }
    }

    @objc func touchUpCloseButton(_ sender: UIButton) {

    }
}

Reference

SnapKit for iOS: Constraints in a Snap

 

SnapKit for iOS: Constraints in a Snap

In this tutorial you’ll learn about SnapKit, a lightweight DSL (domain-specific language) to make Auto Layout and constraints a breeze to work with.

www.kodeco.com

Xcode Workspace

 

Xcode Workspace

Xcode Workspace A workspace is an Xcode document that groups projects and other documents so you can work on them together. A workspace can contain any number of Xcode projects, plus any other files you want to include. In addition to organizing all the fi

developer.apple.com