Skip to content

๐Ÿงฎ ์•„์ดํฐ์˜ ๊ธฐ๋ณธ์•ฑ์ธ ๊ณ„์‚ฐ๊ธฐ ์•ฑ๊ณผ ํก์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ์•ฑ

Notifications You must be signed in to change notification settings

leeari95/ios-calculator-app

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿงฎ ๊ณ„์‚ฐ๊ธฐ ํ”„๋กœ์ ํŠธ

  • ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ
  • ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„: 2021.11.08 ~ 2021.11.19

๋ชฉ์ฐจ


ํ‚ค์›Œ๋“œ

Swift

  • Generic Element
  • map filter split compactMap
  • FloatingPoint Numeric
  • protocol extension
  • attribute
  • replacingOccurrences
  • split vs components

iOS

  • Delegation pattern
  • TDD Unit Test
  • UIStackView UIScrollView
  • NumberFormatter
  • Auto Layout
  • layoutIfNeeded() setNeedsLayout()
  • Main Run Loop Update Cycle
  • viewDidLoad viewWillLayoutSubviews
  • IBInspectable

etc

  • UML
  • Array LinkedList
  • Queue Stack

โญ๏ธ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

์•„์ดํฐ์˜ ๊ธฐ๋ณธ ์•ฑ์ธ ๊ณ„์‚ฐ๊ธฐ ์•ฑ๊ณผ ํก์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง„ ์•ฑ์ด์—์š”. ๐Ÿค“

์‹ฌํ”Œํ•œ UI ๋ฐ ๊ฐ„๋‹จํ•œ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๊ณ„์‚ฐ์„ ํ•  ์ˆ˜ ์žˆ์–ด์š”! ๐Ÿ’ช๐Ÿป


โœจ ํ”„๋กœ์ ํŠธ ์ฃผ์š”๊ธฐ๋Šฅ

๐Ÿงฎ ๋ง์…ˆ, ๋บ„์…ˆ, ๊ณฑ์…ˆ, ๋‚˜๋ˆ—์…ˆ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

๐Ÿ›  ๋ชจ๋‘ ์ดˆ๊ธฐํ™”, ๋ถ€๋ถ„ ์ดˆ๊ธฐํ™”, ํ† ๊ธ€ ๋ฒ„ํŠผ์„ ํ†ตํ•ด ํ˜„์žฌ ๊ณ„์‚ฐ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์–ด์š”.

โœ๐Ÿป ๊ณ„์‚ฐ์ด ๋๋‚˜๊ณ , ์ด์–ด์„œ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์–ด์š”


UML


๐Ÿ›  Trouble Shooting

"์Šคํฌ๋กค์ด ๋จนํžˆ๋Š” ๋ฌธ์ œ"

  • ์ƒํ™ฉ

    • ์Šคํฌ๋กค ๋ทฐ์˜ ์ฝ˜ํ…์ธ  ๋ทฐ ์›์ ์„ ์„ค์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•ด๋ณด์•˜๋‹ค.
    let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
    scrollView.setContentOffset(bottomOffset, animated: false)
    • ๊ทธ๋Ÿฌ๋‚˜ ์Šคํฌ๋กค ๋ฐ”๊ฐ€ ์ƒ๊ธธ๋•Œ ์•ฝ๊ฐ„ ์›€์ง์ด๋ฉด์„œ ์Šคํฌ๋กค์ด ์•ˆ๋˜๋Š”... ์ด์ƒํ•ด๋ณด์ด๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ทจํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.
    • ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๊ธฐ ์œ„ํ•ด์„œ 1์ฐจ์ ์œผ๋กœ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด ์ฐพ์•„๋ณด์•˜๊ณ , ์ฐพ๋Š”๋ฐ ์–ด๋ ค์›€์ด ์žˆ์–ด 3๊ธฐ ์บ ํผ ์„ ๋ฐฐ๋ถ„๋“ค์—๊ฒŒ๋„ ์งˆ๋ฌธํ•ด๋ณด์•˜์ง€๋งŒ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค.
  • ์ด์œ 

    • 3๊ธฐ ์บ ํผ ์ˆ˜๋ฐ•์˜ ๋„์›€์œผ๋กœ LLDB๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ฒ˜์Œ y์ขŒํ‘œ๊ฐ€ ์–ด๋–ค ๊ฐ’์œผ๋กœ ์ฐํžˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์•˜์œผ๋‚˜, StackView๊ฐ€ ์ถ”๊ฐ€๋˜๊ณ  ๋‚œ ํ›„ ์—…๋ฐ์ดํŠธ ๋˜์–ด y๊ฐ’ ์ขŒํ‘œ๊ฐ€ ๊ณ„์‚ฐ์ด ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ธฐ ์ด์ „์˜ y์ขŒํ‘œ๊ฐ€ ์ฐํžˆ๋Š” ๊ฒƒ์ด ํ™•์ธ๋˜์—ˆ๋‹ค.
    • ํƒ€์ด๋จธ๋‚˜ ๋น„๋™๊ธฐ์ ์œผ๋กœ ํ•ด๋‹น ๋ถ€๋ถ„์„ ํ•ด๊ฒฐํ•ด๋ณด๋ ค๊ณ  ํ•ด๋ณด์•˜์œผ๋‚˜ ๋ฐœ๋งŒ ๋‹ด๊ถˆ๋ดค์ง€ ์ œ๋Œ€๋กœ ๋ฐฐ์›Œ๋ณด์ง€ ์•Š์€ ์ง€์‹์ด๋ผ ํ•ด๊ฒฐํ•˜๋Š”๋ฐ ๋งŽ์€ ์–ด๋ ค์›€์ด ์žˆ์—ˆ๋‹ค.
    • ์ดํ›„ ์„œํฌํ„ฐ์ฆˆ Wody์—๊ฒŒ ์งˆ๋ฌธํ•ด๋ณด์•˜๊ณ  ์–ผ๋งˆ ์ง€๋‚˜์ง€ ์•Š์•„ ํ•ด๊ฒฐ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ์ •์ƒ์ ์œผ๋กœ ํ•˜๋‹จ์œผ๋กœ ์ž๋™ ์Šคํฌ๋กค์ด ๋˜๋Š” ๋ชจ์Šต

  • layoutIfNeeded()๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” setNeedsLayout()๊ณผ ๊ฐ™์ด ์ˆ˜๋™์œผ๋กœ layoutSubviews๋ฅผ ์˜ˆ์•ฝํ•˜๋Š” ํ–‰์œ„์ด์ง€๋งŒ ํ•ด๋‹น ์˜ˆ์•ฝ์„ ๋ฐ”๋กœ ์‹คํ–‰์‹œํ‚ค๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋‹ค. update cycle์ด ์˜ฌ ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค layoutSubviews๋ฅผ ํ˜ธ์ถœ์‹œํ‚ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ทธ ์ฆ‰์‹œ layoutSubviews๋ฅผ ๋ฐœ๋™์‹œํ‚ค๋Š” ๋ฉ”์†Œ๋“œ๋‹ค.

  • ๋งŒ์ผ main run loop์—์„œ ํ•˜๋‚˜์˜ View๊ฐ€ setNeedsLayout์„ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ๋‹ค์Œ layoutIfNeeded๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด layoutIfNeeded๋Š” ๊ทธ ์ฆ‰์‹œ View์˜ ๊ฐ’์ด ์žฌ๊ณ„์‚ฐ๋˜๊ณ  ํ™”๋ฉด์— ๋ฐ˜์˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— setNeedsLayout์ด ์˜ˆ์•ฝํ•œ layoutSubviews ๋ฉ”์†Œ๋“œ๋Š” update cycle์—์„œ ๋ฐ˜์˜ํ•ด์•ผํ•  ๋ณ€๊ฒฝ๋œ ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ์ด๋Ÿฌํ•œ ๋™์ž‘ ์›๋ฆฌ๋กœ layoutIfNeeded()๋Š” ๊ทธ ์ฆ‰์‹œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

  • ํ•ด๊ฒฐ

    • ๋”ฐ๋ผ์„œ ์Šคํฌ๋กค๋ทฐ์˜ ์›์ ์— ๋Œ€ํ•œ ์ฝ˜ํ…์ธ ๋ทฐ์˜ ์˜คํ”„์…‹ ์„ค์ •์„ ํ•ด์ฃผ๊ธฐ ์ „์— layoutIfNeeded() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ layout์„ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ  setContentOffset์„ ์„ค์ •ํ•ด์ฃผ์—ˆ๋”๋‹ˆ ํ•ด๋‹น ๋ฌธ์ œ์— ๋Œ€ํ•ด์„œ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.

"๊นŠ์€ ๊ณ„์ธต์— ์œ„์น˜ํ•ด์žˆ๋Š” ๋ทฐ์˜ ์š”์†Œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๊บผ๋‚ด์˜ค๋ ค๋ฉด?"

  • ์ƒํ™ฉ ์Šคํƒ๋ทฐ > ์Šคํƒ๋ทฐ > ๋ ˆ์ด๋ธ” ๊ณ„์ธต์„ ๊ฐ€์ง„ ๋ถ€๋ถ„์—์„œ ๋ ˆ์ด๋ธ”์˜ ํ…์ŠคํŠธ๋ฅผ ๊บผ๋‚ด๋ ค๋ฉด arrangedSubviews๋ฅผ ์ด์ค‘ for๋ฌธ์„ ๋Œ๋ฉด์„œ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ๋งˆ์Œ์— ์•ˆ๋“ค์—ˆ๋‹ค.

    extension UIStackView {
        var toString: String {
            var inputValues = [String]()
                    self.arrangedSubviews.forEach{ view in
                let subview = view as? UIStackView
                subview?.arrangedSubviews.forEach{ view in
                    let label = view as? UILabel
                    guard let input = label?.text else {
                        return
                    }
                    inputValues.append(input.replacingOccurrences(of: ",", with: ""))
                }
            }
            return inputValues.joined(separator: " ")
        }
    }
  • ํ•ด๊ฒฐ๋ฐฉํ–ฅ ๋ฆฌ๋ทฐ์–ด ์—˜๋ฆผ์—๊ฒŒ ์กฐ์–ธ์„ ๊ตฌํ•ด์„œ ์Šคํƒ๋ทฐ > ์ปค์Šคํ…€๋ทฐ ๊ณ„์ธต์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ์ปค์Šคํ…€๋ทฐ ๋งŒ๋“ค๊ธฐ์— ๋„์ „ํ•ด๋ณด์•˜๋‹ค.

  • ๊ฒฐ๊ณผ

    extension UIStackView {
        var toString: String {
            var inputValues = [String]()
            self.arrangedSubviews.forEach { view in
                guard let formualStackView = view as? FormulaStackView else {
                    return
                }
                inputValues.append(contentsOf: formualStackView.element)
            }
            return inputValues.joined(separator: " ")
        }
    }
  • FormulaStackView๋ผ๋Š” ์ปค์Šคํ…€ ๋ทฐ๋ฅผ ๋งŒ๋“ค์–ด ์คŒ์œผ๋กœ์จ ์ด์ค‘ for๋ฌธ์„ ๋Œ๋˜ ๋ฌธ์ œ๋„ ํ•ด๊ฒฐ์ด ๋˜์—ˆ๊ณ , ViewController์—์„œ ์Šคํƒ๋ทฐ ๋‚ด๋ถ€์— Label์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๋ถ€๋ถ„๋„ ์ปค์Šคํ…€๋ทฐ ๋‚ด๋ถ€์—์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ๋˜์—ˆ๋‹ค.

"์Šคํฌ๋กค ๋ฐ”๋กœ ์ธํ•ด ๋‚ด๋ถ€ Label์˜ Text๊ฐ€ ๊ฐ€๋ ค์ง€๋Š” ๋ฌธ์ œ"

  • ์ƒํ™ฉ ๊ณ„์‚ฐ๋‚ด์—ญ์ด ์Œ“์—ฌ์„œ ์Šคํฌ๋กค๋ฐ”๊ฐ€ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ๋กœ ์Šคํฌ๋กค์„ ์ง„ํ–‰ํ•  ์‹œ ๊ธ€์”จ๊ฐ€ ๊ฐ€๋ ค์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.
  • ํ•ด๊ฒฐ๋ฐฉํ–ฅ ์Šคํฌ๋กค๋ฐ”๋ฅผ ๊ฐ€๋ฆด ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋Š”์ง€ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด์„œ ์ฐพ์•„๋ณด์•˜๋‹ค.
  • ๊ฒฐ๊ณผ
  • ์ฐพ์•„๋ณด๋‹ˆ ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”์—์„œ๋„ ์„ค์ •์„ ํ•ด์ค„ ์ˆ˜๋„ ์žˆ๊ณ  ์ฝ”๋“œ๋กœ๋„ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
    • ์ฝ”๋“œ๋กœ ์„ค์ •ํ•˜๊ธฐ

      scrollView.showsHorizontalScrollIndicator = false
      scrollView.showsVerticalScrollIndicator = false
      • ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”์—์„œ ์—†์• ๊ธฐ

      https://i.imgur.com/rOkoBw3.png

      ์œ„ ์‚ฌ์ง„์—์„œ ์ฒดํฌ๋ฅผ ํ’€์–ด์ฃผ๋ฉด ๋œ๋‹ค.

"๋ฒ„ํŠผ์˜ ๋ชจ์–‘์„ ๋‘ฅ๊ธ€๊ฒŒ ๋‹ค๋“ฌ์–ด๋ณด๊ธฐ"

์ƒํ™ฉ ์—˜๋ฆผ์—๊ฒŒ ๋ฒ„ํŠผ์„ ๋‘ฅ๊ธ€๊ฒŒ ๋งŒ๋“ค์–ด๋ณด๋Š” ๋„์ „๊ณผ์ œ๋ฅผ ๋ฐ›๊ฒŒ๋˜์–ด ํ•ด๊ฒฐํ•ด๋ณด๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

์‹œ๋„-1 ์ฒ˜์Œ์—๋Š” ๋ฒ„ํŠผ ์ž์ฒด๊ฐ€ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ์ƒ์„ฑ๋œ ๋ฒ„ํŠผ์ด๋ผ์„œ ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”๋กœ ํ•ด๊ฒฐํ•ด๋ณด๊ณ ์ž ํ•˜์˜€๋‹ค.

    extension UIView {
        @IBInspectable var cornerRadius: CGFloat {
            get {
                return layer.cornerRadius
            }
            set {
                layer.cornerRadius = newValue
                layer.masksToBounds = newValue > 0
            }
        }
    }
  • ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋ฒ„ํŠผ์˜ cornerRadius๋ฅผ ์ง์ ‘ ๋Œ€์ž…ํ•ด์ฃผ๋Š” ๋ฐฉ์‹(ํ•˜๋“œ์ฝ”๋”ฉ)์ด๊ธฐ ๋•Œ๋ฌธ์— ๋””๋ฐ”์ด์Šค๊ฐ€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป๊ธฐ์—๋Š” ํž˜๋“ค๋‹ค๊ณ  ํŒ๋‹จ๋˜์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ฝ”๋“œ๋กœ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„ ํ•ด๊ฒฐํ•ด๋ณด์•˜๋‹ค.

์‹œ๋„-2

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        calculatorButtons.forEach { button in
            button.layer.cornerRadius = button.layer.frame.size.width / 2
        }
    }
  • ๋ฒ„ํŠผ์˜ ๋„ˆ๋น„ / 2๋ฅผ ํ•ด์„œ cornerRadius๋ฅผ ์„ค์ •ํ•ด์ค€ ์ฝ”๋“œ๋‹ค. ์ด๋•Œ viewWillLayoutSubviews ๋ฉ”์†Œ๋“œ๋ฅผ ์จ์ค€๋‹ค.

์‹œ๋„-3, ๊ทธ๋ฆฌ๊ณ  ํ•ด๊ฒฐ

  • ๋ฒ„ํŠผ์˜ IBOutlet์— didSet์„ ์ค„ ์ˆ˜๋„ ์žˆ์—ˆ์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๋ฐฉ๋ฒ•์€ ๋ถˆ๊ฐ€๋Šฅ ํ–ˆ๋‹ค.

  • ๋””๋ฒ„๊น…์„ ํ•ด๋ณด๋‹ˆ viewWillLayoutSubviews ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— ๋ ˆ์ด์•„์›ƒ์ด ๊ฐฑ์‹ ๋˜์–ด ๋ฒ„ํŠผ์˜ ๋„ˆ๋น„๊ฐ€ ๋ฐ”๋€Œ๊ณ  ์žˆ์—ˆ๋‹ค. (๋””๋ฐ”์ด์Šค๋Š” ์•„์ดํฐ SE ๊ธฐ์ค€์ด๋‹ค. SE ์ด์ƒ ๋””๋ฐ”์ด์Šค์—์„œ๋Š” ์—†๋˜ ๋ฌธ์ œ์˜€๋‹ค.) IBOutlet์˜ didSet์€ viewDidLoad๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ์ ์ ˆํ•˜์ง€ ๋ชปํ•œ ๋ฐฉ๋ฒ•์ด์˜€๋‹ค.

  • ๋”ฐ๋ผ์„œ ์ตœ์†Œํ•œ์œผ๋กœ ์ ๊ฒŒ ํ˜ธ์ถœ๋˜๋Š” updateViewConstraints๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

    func setupButtons() {
        calculatorButtons.forEach { button in
            button.layoutIfNeeded()
            button.layer.cornerRadius = button.layer.bounds.width / 2
        }
    }
    
    override func updateViewConstraints() {
        super.updateViewConstraints()
        setupButtons()
    }
  • updateViewConstraints์— ๋ฒ„ํŠผ์…‹ํŒ… ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ ์žˆ๊ณ , for๋ฌธ ๋‚ด๋ถ€์—์„œ ๋ฒ„ํŠผ๋งˆ๋‹ค layoutIfNeeded๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ์„ ๊ฐฑ์‹ ํ•˜๊ณ  ์ดํ›„ cornerRadius ๊ฐ’์„ ๋Œ€์ž…ํ•ด์ฃผ๊ณ ์žˆ๋‹ค.

  • ๋ ˆ์ด์•„์›ƒ์„ ๊ฐฑ์‹ ํ•˜๋Š” ์ด์œ ๋Š” ๊ฐฑ์‹ ํ•˜์ง€ ์•Š์œผ๋ฉด ์œ„ ๋””๋ฒ„๊น…์‹œ ๋ฐœ๊ฒฌํ•˜์˜€๋˜ ์ตœ์ข… ๋ ˆ์ด์•„์›ƒ์ด ์•„๋‹ˆ๋ผ ์ž„์˜๋กœ ์žกํ˜€์žˆ๋˜ frame๊ฐ’์œผ๋กœ ๊ณ„์‚ฐ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์ฒ˜๋Ÿผ ์ฐŒ๊ทธ๋Ÿฌ์ง„ ์›์ด ๋‚˜์˜จ๋‹ค.

๊ฒฐ๋ก 

  • viewDidLoad์—์„œ frame์‚ฌ์ด์ฆˆ๊ฐ€ ์ •ํ™•ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ๋ทฐ๋Š” ๋กœ๋“œ๋๋‹ค๊ณ  ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ฐฐ์น˜๊ฐ€ ๋๋‹ค๊ณ  ํ• ์ˆ˜๋Š” ์—†๋‹ค. ๋”ฐ๋ผ์„œ ์œ„์™€ ๊ฐ™์€ ํ˜„์ƒ์€ viewDidLoad์—์„œ ์ž„์˜๋กœ ์žกํ˜”๋˜ frame๊ฐ’์ด viewWillLayoutSubviews๊ฐ€ ํ˜ธ์ถœํ•˜๋ฉด์„œ ํ•˜์œ„ ๋ทฐ๊ฐ€ ๋ฐฐ์น˜๋˜๊ณ  ์ดํ›„ ๊ฐ’์ด ๋ณ€ํ–ˆ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๊ฒ ๋‹ค. ๋”ฐ๋ผ์„œ ํ•˜์œ„๋ทฐ๊ฐ€ ๋ฐฐ์น˜๊ฐ€ ๋˜๊ณ ๋‚˜์„œ ๋ฒ„ํŠผ์˜ ๋ ˆ์ด์•„์›ƒ์„ ์žก์•„์ค˜์•ผ ํ•ด๊ฒฐ์ด ๊ฐ€๋Šฅํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค.

์—ฌ๊ธฐ์„œ ์˜๋ฌธ์ ์ด ๋“œ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ ๋””๋ฐ”์ด์Šค๋“ค์€ ์ƒ๊ด€์—†๋Š”๋ฐ ์™œ SE์—์„œ๋งŒ ๋ฒ„ํŠผ์˜ ํฌ๊ธฐ๊ฐ€ ์ค„์–ด๋“œ๋Š” ๊ฒƒ์ผ๊นŒ?

  • 3๊ธฐ ์บ ํผ ์ˆ˜๋ฐ• ์˜ ๋„์›€์œผ๋กœ ํ•ด๋‹น ์˜๋ฌธ์ ์„ ํ’€ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

https://i.imgur.com/MiyseWl.png

  • HIG์—์„œ ์žฅ์น˜๋“ค์˜ ์น˜์ˆ˜๋ฅผ ํ™•์ธํ•ด์„œ ์„ธ๋กœ๋ฅผ ๋ณด๋ฉด 200~300์ •๋„ ์ฐจ์ด๊ฐ€ ๋‚˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์ง„์—์„œ๋„ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ์„ธ๋กœ ํฌ๊ธฐ๊ฐ€ ์—„์ฒญ ์ฐจ์ด๋‚œ๋‹ค. ๋”ฐ๋ผ์„œ ์ž‘์•„์ง„ ๋””๋ฐ”์ด์Šค์— ์˜คํ†  ๋ ˆ์ด์•„์›ƒ์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด ๋ฒ„ํŠผ์˜ ํฌ๊ธฐ๋ฅผ ์ค„์ผ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค๋Š” ์ถ”์ธก์ด ๊ฐ€๋Šฅํ•ด์กŒ๋‹ค.
  • ์ด๋Ÿฌํ•œ ์‚ฌ์‹ค์„ ์ฆ๋ช…ํ•ด๋‚ผ ์ˆ˜๋„ ์žˆ๋‹ค. ์ง์ ‘ ๋ ˆ์ด์•„์›ƒ์„ ๋‹ค ๊ณ„์‚ฐํ•˜์—ฌ ์น˜์ˆ˜์™€ ๋งž๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ... ๋‚˜์ค‘์— ์‹œ๋„ํ•ด๋ด์•ผ๊ฒ ๋‹ค. ๐Ÿ˜‡

๐Ÿ”ฅ ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ๊ฒƒ

"Array์— ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด Element๊ฐ€ ๊ธฐ์žฌ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ"

  • ์ƒํ™ฉ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๊ณต๋ถ€ํ•˜๋‹ค๊ฐ€ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ ์ฝ”๋“œ๋“ค์„ ์‚ดํŽด๋ณด๋‹ˆ <T>๋กœ ์ž‘์„ฑ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ณ , <Element>๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ ๋‘˜์˜ ์ฐจ์ด๊ฐ€ ๊ถ๊ธˆํ•ด์กŒ๋‹ค.

  • ์ด์œ  ๊ณต์‹๋ฌธ์„œ Generic ๋ถ€๋ถ„์—์„œ Naming Type Parameters ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณด๋‹ˆ ์ด๋ฆ„์ด ์—†๋Š” ๊ฒƒ๊ณผ ์ด๋ฆ„์ด ์žˆ๋Š” Element๋Š” ์ฐจ์ด๊ฐ€ ์—†์ง€๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ํƒ€์ž… ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„๋•Œ ๋ช…ํ™•ํ•จ์„ ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์—์„œ๋Š” T,ย U, V ๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.
  • ํ•ด๊ฒฐ Array์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Queue๋‚˜ LinkedList๋„ ์š”์†Œ๋“ค์ด ์„œ๋กœ ๊ด€๊ณ„๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ, ํƒ€์ž… ๋‚ด๋ถ€์— ์ œ๋„ค๋ฆญ ํƒ€์ž…<T>์„ Element๋ผ๊ณ  ๋ช…์‹œํ•ด์ฃผ์—ˆ๋‹ค.

"removeAll vs ๋นˆ ๋ฐฐ์—ด ํ• ๋‹นํ•˜๊ธฐ"

  • ์ƒํ™ฉ ๋ฆฌ๋ทฐ์–ด ์—˜๋ฆผ์—๊ฒŒ removeAll๊ณผ ๋นˆ๋ฐฐ์—ด์„ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์ด ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋ƒ๊ณ  ์งˆ๋ฌธ์„ ๋ฐ›์•˜๋Š”๋ฐ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค.
  • ์ด์œ  Swift github๋ฅผ ํ†ตํ•ด removeAll ๋™์ž‘ ๋ฐฉ์‹์„ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.

image

image

  • ํ•ด๊ฒฐ ์‚ดํŽด๋ณด๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’์„ ๋”ฐ๋กœ ture๋กœ ์„ค์ •ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋นˆ Array๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์ฃผ๋Š” ๋™์ž‘์„ ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋นˆ ๋ฐฐ์—ด๊ณผ removeAll๋Š” ํฐ์ฐจ์ด๊ฐ€ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ๋ก ์ด ๋‚ฌ๋‹ค.

"๋นˆ ํ”„๋กœํ† ์ฝœ์˜ ์กด์žฌ ์˜๋ฏธ"

  • ์ƒํ™ฉ STEP 1์„ ์ง„ํ–‰ํ•  ๋•Œ ๋นˆ ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•ด๋‘๋ผ๋Š” ๋ถ€๋ถ„์—์„œ ์ž˜ ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š์•˜๋‹ค.
  • ์ด์œ  ์•Œ๊ณ ๋ณด๋‹ˆ CalculateItem์€ Queue์—์„œ ๋‹ค๋ฃจ๋Š” ์š”์†Œ๊ฐ€ ์ค€์ˆ˜ํ•ด์•ผํ–ˆ๋˜ ํ”„๋กœํ† ์ฝœ์ด์˜€๋‹ค.
  • ํ•ด๊ฒฐ STEP 2๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด์„œ ํ•ด๋‹น ํ”„๋กœํ† ์ฝœ์˜ ์—ญํ• ์„ ์ž˜ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ๋•๋ถ„์— ๋นˆ ํ”„๋กœํ† ์ฝœ์˜ ์šฉ๋„์— ๋Œ€ํ•ด์„œ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.

"split vs components"

  • ์ƒํ™ฉ ์—˜๋ฆผ์—๊ฒŒ ์งˆ๋ฌธ์„ ๋ฐ›์•˜๋Š”๋ฐ ๋‚ด๊ฐ€ ์•Œ๊ณ ์žˆ๋˜ ์ฐจ์ด์ ์€ ๋ฐ˜ํ™˜ํƒ€์ž… ๋ฟ์ด์˜€๋‹ค.

  • ์ด์œ  ๋ฐ˜ํ™˜ํƒ€์ž… ๋ง๊ณ ๋„ ๋‹ค๋ฅธ ์ฐจ์ด์ ๋„ ์žˆ์—ˆ๋˜๊ฒŒ ์ƒ๊ฐ๋‚˜์„œ ์ •๋ฆฌํ•ด๋ณด์•˜๋‹ค.

  • ํ•ด๊ฒฐ

  • import ์—ฌ๋ถ€

    • split์€ swift ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์†ํ•ด์žˆ๋‹ค.
    • components๋Š” Foundation ํ”„๋ ˆ์ž„์›Œํฌ์— ์†ํ•ด์žˆ์–ด importํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํŒŒ๋ผ๋ฏธํ„ฐ

    • split(separator: Character, maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true)
    • components(separatedBy separator: String)
  • ๊ณต๋ฐฑ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ์˜ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ

    let str = "My name is Sudhir " // trailing space
    
        str.split(separator: " ")
        // ["My", "name", "is", "Sudhir"]
    
        str.components(separatedBy: " ")
        // ["My", "name", "is", "Sudhir", ""] โ† Additional empty string

    ๋‘˜๋‹ค ๋™์ผํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ํ•˜๋ ค๋ฉด split์˜ ํŒŒ๋ผ๋ฏธํ„ฐย omittingEmptySubsequences๋ฅผ false๋กœ ์˜ต์…˜์„ ๋”ฐ๋กœ ์ค˜์•ผ ๊ฐ€๋Šฅํ•˜๋‹ค.

    str.split(separator: " ", omittingEmptySubsequences: false)
        // ["My", "name", "is", "Sudhir", ""]
  • ๋ฐ˜ํ™˜ํƒ€์ž…์˜ ์ฐจ์ด

    • split -> [Substring]
    • components -> [String]
  • ์„ฑ๋Šฅ ์ฐจ์ด ๋ฐ˜ํ™˜ํƒ€์ž…์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏย split์€ ์›๋ณธ ๋ฌธ์ž์—ด์„ ์ฐธ์กฐ(SubString)ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ƒˆ ๋ฌธ์ž์—ด์„ ํ• ๋‹นํ•˜์ง€ ์•Š๋Š”๋‹ค.๋”ฐ๋ผ์„œ split์ด components๋ณด๋‹ค ์„ฑ๋Šฅ์ธก๋ฉด์—์„œ ๋น ๋ฅด๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

    Substring์ด๋ž€?์›๋ณธ ๋ฌธ์ž์—ด์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•œ๋‹ค.๊ฐ’์„ ์ฝ๊ธฐ๋งŒ ํ•  ๋•Œ๋Š” ์›๋ณธ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๊ณ , ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ์‹œ์ ์—๋งŒ ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

    Substring์€ ์ฃผ๋กœ ๋ฌธ์ž์—ด์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•˜๊ธฐ ์œ„ํ•ด์„œ ์“ฐ์ด๋Š” ํƒ€์ž…์œผ๋กœ ์•Œ๊ณ ์žˆ๋‹ค!

"viewWillLayoutSubviews()๋Š” ๋ฌด์Šจ ์—ญํ• ์„ ํ• ๊นŒ?"

  • ๋ทฐ์˜ ๋ฐ”์šด๋“œ๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ ๊ฒฐ์ •๋˜๋Š” ์ตœ์ดˆ ์‹œ์ 
  • ์ œ์•ฝ์ด๋‚˜ ์˜คํ† ๋ ˆ์ด์•„์›ƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์„œ๋ธŒ๋ทฐ์˜ ๋ ˆ์ด์•„์›ƒ์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์ ํ•ฉํ•œ ์‹œ์ ์ด๋‹ค.
  • ์—ฌ๋Ÿฌ๋ฒˆ ์ค‘๋ณต์œผ๋กœ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค.
    • ex) ๋ฉ”์ธ๋ทฐ์˜ ์„œ๋ธŒ๋ทฐ๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๊ฒฝ์šฐ
  • ๋ฉ”์†Œ๋“œ๋ฅผ ์•Œ์•„๋ณด๊ณ  ์—˜๋ฆผ์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ  ๋‹ค์‹œ ๋””๋ฒ„๊น…์„ ํ•ด๋ณด๋‹ˆ ๋ฒ„ํŠผ์ด ํด๋ฆญ์ด ๋˜๋Š” ์‹œ์ ๋งˆ๋‹ค ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ์ด ๋˜๊ณ ์žˆ์—ˆ๋‹ค. cornerRadius๋ฅผ ์žก์•„์ฃผ๋Š” for๋ฌธ์ด ๋ฒ„ํŠผ์ด ๋ˆ„๋ฅผ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋˜๊ณ  ์žˆ์—ˆ๋˜ ๊ฒƒ์ด๋‹ค. ์ฆ‰ SubView์˜ ๋ ˆ์ด์•„์›ƒ์„ ์žก์•„์ฃผ๊ธฐ์—๋Š” ์ ์ ˆ์น˜ ๋ชปํ•œ ๋ฉ”์†Œ๋“œ์˜€๋‹ค.

๐Ÿ’ช๐Ÿป ๊ธฐ์ˆ ์  ๋„์ „

Delegate Pattern

  • MVC ๊ตฌ์กฐ๋กœ ์ธํ•ด ๋šฑ๋šฑํ•ด์ง„ ViewController๋ฅผ ๋‹ค์ด์–ดํŠธ ์‹œ์ผœ์ฃผ๊ธฐ ์œ„ํ•ด Delegate ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ถ€๋ถ„์„ ๋ณ„๋„์˜ ํƒ€์ž…์œผ๋กœ ๋งŒ๋“ค์–ด ์ฑ…์ž„์„ ๋‚˜๋ˆ„์–ด์ฃผ์–ด ViewController์˜ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋†’์•„์ง€๊ณ , ์—ญํ•  ๋˜ํ•œ ๋ช…ํ™•ํžˆ ๋‚˜๋ˆ„์–ด์กŒ์Šต๋‹ˆ๋‹ค.

top

[ํ•™์Šต ๊ธฐ๋ก ํ”์ ]

๋ชฉ์ฐจ

STEP 1 : Queue ํƒ€์ž… ๊ตฌํ˜„

  • ์ž๋ฃŒ๊ตฌ์กฐ Queue ํƒ€์ž…์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

UML

top

1-1 ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ

  • Queue๋ฅผ DoubleStack๊ณผ LinkedList๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‘๊ฐ€์ง€๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค. ๋ฐฐ์—ด๋กœ๋„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ enqueue ์ž‘์—…์ด ์‹œ๊ฐ„๋ณต์žก๋„๊ฐ€ O(1)์ด ๊ฑธ๋ ค์„œ ๋น„ํšจ์œจ์ ์ด๋‹ค.
  • Genericํƒ€์ž…์„ ์‚ฌ์šฉํ•  ๋•Œ Element๋กœ ๋ช…์‹œํ•ด์ฃผ์—ˆ๋‹ค. ์ด์œ ๋Š” T๋กœ ๋ช…์‹œํ•ด์ค„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์–ด๋–ค ํƒ€์ž…์ด ๋“ค์–ด๊ฐˆ์ง€ ๋ช…ํ™•ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ข€๋” ์ง๊ด€์ ์œผ๋กœ ๋ณด์ผ ์ˆ˜ ์žˆ๋„๋ก ์š”์†Œ๋ผ๋Š” ๋œป์„ ๋‹ด์€ Element๋ฅผ ๋ช…์‹œํ–ˆ๋‹ค.

1-2 ์˜๋ฌธ์ 

  • Queue๋ฅผ ๋ฐฐ์—ด๋กœ ๊ตฌํ˜„ํ•ด๋„ ๊ดœ์ฐฎ์„๊นŒ?
  • Array์— ์ œ๋„ค๋ฆญ ํƒ€์ž…์€ ์–ด์งธ์„œ Element์ผ๊นŒ?
  • removeAll๊ณผ ๋นˆ ๋ฐฐ์—ด์„ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ๊ณผ ์ฐจ์ด์ ์ด ๋ญ˜๊นŒ?

1-3 Trouble Shooting

1. Array์— ์ œ๋„ค๋ฆญ ํƒ€์ž…์ด Element๊ฐ€ ๊ธฐ์žฌ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ

  • ์ƒํ™ฉ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๊ณต๋ถ€ํ•˜๋‹ค๊ฐ€ ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ ์ฝ”๋“œ๋“ค์„ ์‚ดํŽด๋ณด๋‹ˆ <T>๋กœ ์ž‘์„ฑ๋˜์–ด์žˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ณ , <Element>๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ ๋‘˜์˜ ์ฐจ์ด๊ฐ€ ๊ถ๊ธˆํ•ด์กŒ๋‹ค.

  • ์ด์œ  ๊ณต์‹๋ฌธ์„œ Generic ๋ถ€๋ถ„์—์„œ Naming Type Parameters ๋ถ€๋ถ„์„ ์‚ดํŽด๋ณด๋‹ˆ ์ด๋ฆ„์ด ์—†๋Š” ๊ฒƒ๊ณผ ์ด๋ฆ„์ด ์žˆ๋Š” Element๋Š” ์ฐจ์ด๊ฐ€ ์—†์ง€๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ํƒ€์ž… ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์„๋•Œ ๋ช…ํ™•ํ•จ์„ ์ฃผ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ด€๊ณ„๊ฐ€ ์—†๋Š” ์ƒํ™ฉ์—์„œ๋Š” T,ย U, V ๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ํ•œ๋‹ค.
  • ํ•ด๊ฒฐ Array์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Queue๋‚˜ LinkedList๋„ ์š”์†Œ๋“ค์ด ์„œ๋กœ ๊ด€๊ณ„๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ, ํƒ€์ž… ๋‚ด๋ถ€์— ์ œ๋„ค๋ฆญ ํƒ€์ž…<T>์„ Element๋ผ๊ณ  ๋ช…์‹œํ•ด์ฃผ์—ˆ๋‹ค.

2. removeAll vs ๋นˆ ๋ฐฐ์—ด ํ• ๋‹นํ•˜๊ธฐ

  • ์ƒํ™ฉ ์—˜๋ฆผ์—๊ฒŒ removeAll๊ณผ ๋นˆ๋ฐฐ์—ด์„ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์ด ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋ƒ๊ณ  ์งˆ๋ฌธ์„ ๋ฐ›์•˜๋Š”๋ฐ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ๋‹ค.
  • ์ด์œ  Swift github๋ฅผ ํ†ตํ•ด removeAll ๋™์ž‘ ๋ฐฉ์‹์„ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.

image

image

  • ํ•ด๊ฒฐ ์‚ดํŽด๋ณด๋‹ˆ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ณธ๊ฐ’์„ ๋”ฐ๋กœ ture๋กœ ์„ค์ •ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋นˆ Array๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด์ฃผ๋Š” ๋™์ž‘์„ ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋นˆ ๋ฐฐ์—ด๊ณผ removeAll๋Š” ํฐ์ฐจ์ด๊ฐ€ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ๋ก ์ด ๋‚ฌ๋‹ค.

1-4 ๋ฐฐ์šด ๊ฐœ๋…

  • Element์˜ ์šฉ๋„
  • ์ž๋ฃŒ๊ตฌ์กฐ (Array, LinkedList, Queue, Stack)
  • ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์‹œ๊ฐ„๋„์™€ Big-O
  • removeAll๊ณผ ๋นˆ ๋ฐฐ์—ด์„ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ ํฐ ์ฐจ์ด๊ฐ€ ์—†๋‹ค.

1-5 PR ํ›„ ๊ฐœ์„ ์‚ฌํ•ญ

  • ๋ถˆํ•„์š”ํ•œ import ์ œ๊ฑฐ
  • ์ถ”๊ฐ€์ ์œผ๋กœ attribute์— ๋Œ€ํ•ด์„œ ๊ณต๋ถ€ํ•ด๋ณด๊ธฐ.
  • ์งง์€ return๋ฌธ์ด๋ผ๋„ ์ค„๋ฐ”๊ฟˆ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋””๋ฒ„๊น… ์‹œ ์œ ์šฉํ•˜๋‹ค.
  • ๋ฉ”์„œ๋“œ ํƒˆ์ถœํ•˜๋Š” ๋ถ€๋ถ„์€ ๋ณดํ†ต if๋ณด๋‹ค๋Š” guard๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

top

STEP 2 : ๊ณ„์‚ฐ ํƒ€์ž… ๋ฐ ์ฃผ๋ณ€ ํƒ€์ž… ๊ตฌํ˜„

  • ๊ณ„์‚ฐ ํƒ€์ž…์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

2-1 ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ

์ด๋ฒˆ ์Šคํ… ์ง„ํ–‰์„ ์œ„ํ•ด ์ €์™€ ๊ณ ๋ฏผ์„ ๋‚˜๋ˆ ์ฃผ์…จ๋˜ ์บ ํผ๋ถ„๋“ค์—๊ฒŒ ๊ฐ์‚ฌ์˜ ์ธ์‚ฌ๋ฅผ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.


  • ์ฃผ์–ด์ง„ UML์„ ๋ณด๋ฉฐ ํƒ€์ž…์ด ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์œ ์ถ”ํ•˜๋ฉด์„œ ์ •๋ฆฌํ•ด๋ณด์•˜๋‹ค.

ExpressionParser

  • ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ ๊ฒ€์‚ฌํ•ด์„œ ์—ฐ์‚ฐ์ž์™€ ํ”ผ์—ฐ์‚ฐ์ž๋ฅผ ๋‹ด๋Š” Formula๋ฅผ ๋งŒ๋“œ๋Š” ํƒ€์ž…
    • componentsByOperators
      • input์„ ๋ฐ›์•„์„œ ์ˆซ์ž๋งŒ ๋ฝ‘์•„์˜ค๋Š” ๋ฉ”์†Œ๋“œ
    • parse
      • ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋ฐ›์•„์„œ Formula๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ

extension String

  • split(with:)
    • target์„ ๊ธฐ์ค€์œผ๋กœ ๋ฌธ์ž์—ด์„ ์ž˜๋ผ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์†Œ๋“œ ์˜ˆ์‹œ) "12 + 3.1" โ†’ ["12", "+", "3.1"]

Formula

  • ์—ฐ์‚ฐ์žํ์™€ ํ”ผ์—ฐ์‚ฐ์žํ๋ฅผ ๋‹ด๊ณ , ๊ฒฐ๊ณผ(result())๋ฅผ ๋‚ด๋Š” ํƒ€์ž…

Operator

  • ์—ฐ์‚ฐ์ž์™€ ๊ณ„์‚ฐ ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๋Š” ํƒ€์ž…

split์˜ ๋กœ์ง์— ๊ด€ํ•œ ๋‹ค์–‘ํ•œ ๊ณ ๋ฏผ

  • ์ฒซ๋ฒˆ์งธ๋Š” split์„ ํ™•์žฅํ•œ๋‹ค๋Š” ์˜๋ฏธ ์ž์ฒด๊ฐ€ ๊ธฐ์กด split๊ณผ์˜ ๊ธฐ๋Šฅ์ด ๋‹ค๋ฅด๋‹ค๊ณ  ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ target๊ณผ ํ•จ๊ป˜ ์ž๋ฅด๋Š” ๊ฒƒ์ธ๊ฐ€? ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ์—ฐ์‚ฐ์ž์™€ Double ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” ์ˆซ์ž๊ฐ€ ํ•จ๊ป˜ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜๋˜์–ด Formula๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ๋กœ์ง์„ ์ƒ๊ฐํ•ด๋ณด์•˜๋‹ค.
  • ์œ„์—์„œ ์ƒ๊ฐํ•œ ๋กœ์ง์œผ๋กœ ๋จผ์ € ๋Œ์•„๊ฐ€๊ฒŒ๋” ๊ตฌํ˜„์„ ํ•ด๋ณด์•˜๋”๋‹ˆ target์„ ์•ˆ์“ฐ๊ฒŒ ๋˜์—ˆ๋‹ค. ๋จผ์ € ๊ณ ๋ คํ–ˆ๋˜ ๊ฒƒ์€ ์ˆซ์ž, ์—ฐ์‚ฐ์ž๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ๋“ค์–ด์˜จ๋‹ค๋Š” ๊ฐ€์ •ํ•˜์— ๊ตฌํ˜„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. target์ด ์•ˆ์“ฐ์ด๋Š” ๊ฒƒ์ด ๋„ˆ๋ฌด ์ฐ์ฐํ•˜์—ฌ ์—ฌ๋Ÿฌ ์บ ํผ๋ถ„๋“ค๊ณผ ๊ฐ™์ด ๊ณ ๋ฏผ์„ ๋‚˜๋ˆ„์–ด๋ณด์•˜๋‹ค.
  • ๋งŽ์€ ๊ณ ๋ฏผ๋“ค ๋์— ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ ์ˆซ์ž์™€ ์—ฐ์‚ฐ์ž๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ • ๋ฌธ์ž์—ด์„ ์ž„์˜๋กœ ๋„ฃ์–ด ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์„ ๊ณต์œ ๋ฐ›์•˜๋‹ค. (chacha ๊ณ ๋ง™์Šต๋‹ˆ๋‹ค...๐Ÿ˜ญ) ๊ทธ๋ž˜์„œ ์—ฐ์‚ฐ์ž๋ฅผ ๋ˆ„๋ฅผ ๋•Œ ๋งˆ๋‹ค ์•ž ๋’ค๋กœ ๊ณต๋ฐฑ์ด ์ถ”๊ฐ€๋˜๋Š” ๋กœ์ง์ด ๋– ์˜ฌ๋ผ์„œ ๊ทธ๋Œ€๋กœ ์˜ฎ๊ฒจ์„œ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.
  • ๊ทธ๋Ÿฌ๋‚˜ Operator ํƒ€์ž…์ด Character์ธ ๋ถ€๋ถ„๊ณผ CaseIterable ํ”„๋กœํ† ์ฝœ์„ ์ฑ„ํƒํ•œ ๊ฒƒ์„ ๋ณด์•˜์„ ๋•Œ ์ด๊ฒƒ์„ split์„ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„๊นŒ? ๋ผ๋Š” ์˜๋ฌธ์ด ๋˜ ์ƒ๊ฒผ๋‹ค. ์‚ฌ์‹ค ๊ณต๋ฐฑ์„ ์ถ”๊ฐ€ํ•ด์„œ ์ž˜๋ผ์ค„ ์ˆ˜๋„ ์žˆ๊ฒ ์ง€๋งŒ ํ•˜๋“œ์ฝ”๋”ฉ์ด๋ผ๋Š” ์ƒ๊ฐ์ด ๋จผ์ € ๋“ค์—ˆ๋‹ค. ์ดํ›„ Operator์˜ rawValue๋ฅผ ์ด์šฉํ•˜์—ฌ split์„ ๊ตฌํ˜„ํ•ด๋ณผ๊นŒ ๊ณ ๋ฏผํ•ด๋ณด์•˜์ง€๋งŒ.. ์ผ๋‹จ target์˜ ํƒ€์ž…์ด ๋ฐฐ์—ด์ด ์•„๋‹Œ ๋ถ€๋ถ„๊ณผ allcases๋ฅผ ์‚ฌ์šฉํ•ด์„œ rawValue๋ฅผ ๋ฝ‘์•„์˜ฌ ์ˆ˜ ์—†๋Š” ์  ๋•Œ๋ฌธ์— ํ•ด๋‹น ์˜๋ฌธ์ ์€ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•˜์˜€๋‹ค.

dequeueํ•  ๋•Œ ์˜ต์…”๋„๋ฐ”์ธ๋”ฉ์„ ํ•  ๊ฒƒ์ธ์ง€? ์—๋Ÿฌ์ฒ˜๋ฆฌ๋ฅผ ํ•  ๊ฒƒ์ธ์ง€?

  • ์›๋ž˜๋Š” dequeue๋ฅผ ํ•  ๋•Œ nil์ด ๋ฐ˜ํ™˜ ๋˜๊ฒŒ๋” ๊ตฌํ˜„์„ ํ•˜์˜€์—ˆ๋Š”๋ฐ, ์ผ์ผํžˆ ์˜ต์…”๋„ ๋ฐ”์ธ๋”ฉ ์ฒ˜๋ฆฌ ํ•ด์ฃผ๋ฉด ์ง€์ €๋ถ„ํ•ด์ง€๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ ํ•ด๋‹น ๋กœ์ง์„ ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋Š” ๋กœ์ง์œผ๋กœ ๋ฐ”๊พธ์–ด์ฃผ์—ˆ๋‹ค. ์ดํ›„์—๋„ ๊ณ„์† ์ฝ”๋“œ๊ฐ€ ๋”๋Ÿฝ๋‹ค๊ณ  ๋Š๊ปด์ ธ์„œ ๋‹ค์‹œ ๊ณ ๋ฏผํ•ด๋ณด๋‹ค๊ฐ€... nil์ด ๋ฐ˜ํ™˜ํ•˜๊ฒŒ๋” ์žฌ์ˆ˜์ •์„ ํ•ด์ฃผ๊ณ  result ๋ถ€๋ถ„์„ ์ƒˆ๋กœ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค.

parse์—์„œ Double๋ฐฐ์—ด๊ณผ Operator๋ฐฐ์—ด์„ nil ์ฒดํฌ ํ›„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ธฐ

  • ์ฒ˜์Œ์—๋Š” compactMap์˜ ๋กœ์ง์„ ์ฐธ๊ณ ํ•˜์—ฌ filter์™€ map์„ ์ด์šฉํ•˜์—ฌ nil ์ฒดํฌ๋ฅผ ํ•˜์—ฌ ๋ณ€ํ™˜ํ•ด์ฃผ์—ˆ์—ˆ๋Š”๋ฐ, ๊ทธ๋Ÿด ํ•„์š” ์—†์ด compactMap์„ ์‚ฌ์šฉํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋„ค? ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ ์ˆ˜์ •ํ•ด์ฃผ์—ˆ๋‹ค.

๊ธฐ์กด์— ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋˜ Model์˜ ์ด๋‹ˆ์…œ๋ผ์ด์ € ์ถ”๊ฐ€

  • STEP 1์—์„œ ๊ตฌํ˜„ํ•ด์ค„ ๋•Œ์—๋Š” ์ด๋‹ˆ์…œ๋ผ์ด์ €๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ์ง€ ์•Š์•˜์—ˆ๋Š”๋ฐ, STEP 2๋ฅผ ๊ตฌํ˜„ํ•˜๋‹ค๋ณด๋‹ˆ ์ด๋‹ˆ์…œ๋ผ์ด์ €๋ฅผ ํ†ตํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ์ˆœ๊ฐ„์ด ์˜ค๊ฒŒ๋˜์–ด ์ด๋‹ˆ์…œ๋ผ์ด์ €๋ฅผ ๋ชจ๋‘ ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋‹ค.

2-2 ์˜๋ฌธ์ 

  • split(with:) ๋ฉ”์†Œ๋“œ์˜ ์—ญํ• ์ด ์ •ํ™•ํžˆ ๋ญ˜๊นŒ?
  • dequeue์‹œ ์˜ต์…”๋„๋ฐ”์ธ๋”ฉ vs ์—๋Ÿฌํ•ธ๋“ค๋ง
  • NaN์€ ์–ด๋–ค ์‹œ์ ์— ๋ฐœ์ƒํ•˜๋Š” ๊ฑธ๊นŒ?
  • componentsByOperators ๋ฉ”์„œ๋“œ๋ช…์ด ๋™์‚ฌ๊ฐ€ ์—†๋Š” ๊ฒƒ ๊ฐ™๋‹ค. ์ ์ ˆํ•œ ๊ฑธ๊นŒ?

2-3 Trouble Shooting

1. ๋นˆ ํ”„๋กœํ† ์ฝœ์˜ ์กด์žฌ ์˜๋ฏธ๊ฐ€ ๋ญ˜๊นŒ?

  • ์ƒํ™ฉ STEP 1์„ ์ง„ํ–‰ํ•  ๋•Œ ๋นˆ ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•ด๋‘๋ผ๋Š” ๋ถ€๋ถ„์—์„œ ์ž˜ ์ดํ•ด๊ฐ€ ๊ฐ€์ง€ ์•Š์•˜๋‹ค.
  • ์ด์œ  ์•Œ๊ณ ๋ณด๋‹ˆ CalculateItem์€ Queue์—์„œ ๋‹ค๋ฃจ๋Š” ์š”์†Œ๊ฐ€ ์ค€์ˆ˜ํ•ด์•ผํ–ˆ๋˜ ํ”„๋กœํ† ์ฝœ์ด์˜€๋‹ค.
  • ํ•ด๊ฒฐ STEP 2๋ฅผ ์ง„ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด์„œ ํ•ด๋‹น ํ”„๋กœํ† ์ฝœ์˜ ์—ญํ• ์„ ์ž˜ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ๋•๋ถ„์— ๋นˆ ํ”„๋กœํ† ์ฝœ์˜ ์šฉ๋„์— ๋Œ€ํ•ด์„œ ์•Œ๊ฒŒ๋˜์—ˆ๋‹ค.

2. UML ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ ํ™”์‚ดํ‘œ์— ๋Œ€ํ•ด์„œ

  • ์ƒํ™ฉ STEP 2์—์„œ ์ฃผ์–ด์กŒ๋˜ UML์— ๋Œ€ํ•œ ์˜๋ฌธ์ด ์ƒ๊ฒผ๋‹ค. ์™œ ๋‚ด๋ถ€์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด์žˆ๋Š” ํƒ€์ž…๋ผ๋ฆฌ๋Š” ํ™”์‚ดํ‘œ ํ‘œ์‹œ๊ฐ€ ์—†์„๊นŒ?
  • ์ด์œ  ์ด๋Ÿฌํ•œ ๊ถ๊ธˆ์ ์„ ์˜ค๋™๋‚˜๋ฌด์—๊ฒŒ ์ง์ ‘ ์งˆ๋ฌธํ•ด๋ณด์•˜๋‹ค.
  • ํ•ด๊ฒฐ ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ์€ ํ‘œ๋ฉด์ ์œผ๋กœ ๋“œ๋Ÿฌ๋‚œ ๊ด€๊ณ„๋งŒ ๋‚˜ํƒ€๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด๋ถ€ ๊ตฌํ˜„์— ๋Œ€ํ•ด์„œ๋Š” ํ™”์‚ดํ‘œ๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ๋‹ค.

3. ๋ฉ”์†Œ๋“œ๋ช…์€ ๋™์‚ฌ๋กœ ์ง€์–ด์•ผํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€?

  • ์ƒํ™ฉ ๋ฆฌ๋ทฐ์–ด ์—˜๋ฆผ์—๊ฒŒ ๋ฐ›์€ ํ”ผ๋“œ๋ฐฑ์„ ๊ณ ๋ฏผํ•ด๋ณด๋‹ค๊ฐ€ ๋ฉ”์†Œ๋“œ๋ช…์ด ์ด์ƒํ•˜๋‹ค๋Š” ์˜๋ฌธ์ ์ด ์ƒ๊ฒจ UML์„ ์ž‘์„ฑํ–ˆ๋˜ ์˜ค๋™๋‚˜๋ฌด์—๊ฒŒ ์งˆ๋ฌธํ•ด๋ณด์•˜๋‹ค.
  • ์ด์œ  ์บ ํผ๋“ค๊ณผ ์ด์•ผ๊ธฐ๋ฅผ ๋‚˜๋ˆ„์–ด๋ดค๋Š”๋ฐ, ๋ฉ”์†Œ๋“œ๋ช…์— ๋™์‚ฌ๊ฐ€ ํฌํ•จ๋˜์–ด์žˆ์ง€ ์•Š์•˜๋‹ค. ์œ ์ถ”ํ•œ ๊ธฐ๋Šฅ์œผ๋กœ๋Š” split๊ณผ ๊ฐ™์€ ๋™์ž‘์„ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ ๊ฐ™์€๋ฐ, Int.random ๊ฐ™์€ ๋งฅ๋ฝ์œผ๋กœ get์„ ์ƒ๋žตํ•œ ๊ฒฝ์šฐ์ธ๊ฑธ๊นŒ?
  • ํ•ด๊ฒฐ ํ•ด๋‹น ๋ถ€๋ถ„์„ ์˜ค๋™๋‚˜๋ฌด์—๊ฒŒ ์ง์ ‘ ๋ฌผ์–ด๋ณด์•˜๊ณ , ์œ„ ๋‚ด์šฉ๊ณผ ๊ฐ™์€ ๋งฅ๋ฝ์œผ๋กœ ๋™์‚ฌ๊ฐ€ ์•„๋‹Œ ๋„ค์ด๋ฐ์„ ํ•œ ๊ฒƒ์ด ๋งž๋‹ค๊ณ  ๋‹ต๋ณ€๋ฐ›์•˜๋‹ค. Swift๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ์—†์ด ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋Š” ๋ฉ”์„œ๋“œ์— get์„ ๋ถ™์ด๋Š” ๊ฒƒ์„ ์ง€์–‘ํ•˜๋Š” ํŽธ์ด๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ ์ฝ”์ฝ”์•„ํ„ฐ์น˜ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ get, fetch, request๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋Š” ์ „๋ถ€ completion handler๋ฅผ ๋ฐ›๋Š” ๋น„๋™๊ธฐ ์ž‘์—… ๋ฟ์ด๋‹ค.

4. split vs components

  • ์ƒํ™ฉ ์—˜๋ฆผ์—๊ฒŒ ์งˆ๋ฌธ์„ ๋ฐ›์•˜๋Š”๋ฐ ๋‚ด๊ฐ€ ์•Œ๊ณ ์žˆ๋˜ ์ฐจ์ด์ ์€ ๋ฐ˜ํ™˜ํƒ€์ž… ๋ฟ์ด์˜€๋‹ค.

  • ์ด์œ  ๋ฐ˜ํ™˜ํƒ€์ž… ๋ง๊ณ ๋„ ๋‹ค๋ฅธ ์ฐจ์ด์ ๋„ ์žˆ์—ˆ๋˜๊ฒŒ ์ƒ๊ฐ๋‚˜์„œ ์ •๋ฆฌํ•ด๋ณด์•˜๋‹ค.

  • ํ•ด๊ฒฐ

    import ์—ฌ๋ถ€

    • split์€ swift ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์†ํ•ด์žˆ๋‹ค.
    • components๋Š” Foundation ํ”„๋ ˆ์ž„์›Œํฌ์— ์†ํ•ด์žˆ์–ด importํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    ํŒŒ๋ผ๋ฏธํ„ฐ

    • split(separator: Character, maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true)
    • components(separatedBy separator: String)

    ๊ณต๋ฐฑ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ์˜ ๋‹ค๋ฅธ ๊ฒฐ๊ณผ

    let str = "My name is Sudhir " // trailing space
    
        str.split(separator: " ")
        // ["My", "name", "is", "Sudhir"]
    
        str.components(separatedBy: " ")
        // ["My", "name", "is", "Sudhir", ""] โ† Additional empty string

    ๋‘˜๋‹ค ๋™์ผํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๊ฒŒ ํ•˜๋ ค๋ฉด split์˜ ํŒŒ๋ผ๋ฏธํ„ฐย omittingEmptySubsequences๋ฅผ false๋กœ ์˜ต์…˜์„ ๋”ฐ๋กœ ์ค˜์•ผ ๊ฐ€๋Šฅํ•˜๋‹ค.

    str.split(separator: " ", omittingEmptySubsequences: false)
        // ["My", "name", "is", "Sudhir", ""]

    ๋ฐ˜ํ™˜ํƒ€์ž…์˜ ์ฐจ์ด

    • split -> [Substring]
    • components -> [String]

    ์„ฑ๋Šฅ ์ฐจ์ด

    ๋ฐ˜ํ™˜ํƒ€์ž…์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏย split์€ ์›๋ณธ ๋ฌธ์ž์—ด์„ ์ฐธ์กฐ(SubString)ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ƒˆ ๋ฌธ์ž์—ด์„ ํ• ๋‹นํ•˜์ง€ ์•Š๋Š”๋‹ค.๋”ฐ๋ผ์„œ split์ด components๋ณด๋‹ค ์„ฑ๋Šฅ์ธก๋ฉด์—์„œ ๋น ๋ฅด๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

    Substring์ด๋ž€?์›๋ณธ ๋ฌธ์ž์—ด์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•œ๋‹ค.๊ฐ’์„ ์ฝ๊ธฐ๋งŒ ํ•  ๋•Œ๋Š” ์›๋ณธ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๊ณ , ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ์‹œ์ ์—๋งŒ ์ƒˆ๋กœ์šด ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

    Substring์€ ์ฃผ๋กœ ๋ฌธ์ž์—ด์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•˜๊ธฐ ์œ„ํ•ด์„œ ์“ฐ์ด๋Š” ํƒ€์ž…์œผ๋กœ ์•Œ๊ณ ์žˆ๋‹ค!

2-4 ๋ฐฐ์šด ๊ฐœ๋…

  • ๋นˆ ํ”„๋กœํ† ์ฝœ์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ๊ณ ์ฐจํ•จ์ˆ˜์˜ ๋™์ž‘ ๋ฐฉ์‹
  • UML ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ
  • NaN
  • ๋ฉ”์†Œ๋“œ๋ช…์— get ์‚ฌ์šฉ์„ ์˜ฌ๋ฐ”๋ฅธ ์ƒํ™ฉ์— ํ•˜๋Š” ๋ฐฉ๋ฒ•
  • split๊ณผ components์˜ ์ฐจ์ด์ 

2-5 PR ํ›„ ๊ฐœ์„ ์‚ฌํ•ญ

  • ๋†“์ณค๋˜ ๋ชจํ˜ธํ•œ ๋ถ€๋ถ„์„ ์—๋Ÿฌ๋ฅผ ๋˜์ง€๋„๋ก ๊ฐœ์„ ํ•˜์˜€๋‹ค.
  • split๊ณผ components์˜ ์ฐจ์ด์ ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.
  • ๋ฉ”์†Œ๋“œ๋ช…์— get์€ ์–ธ์ œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค.

top

STEP 3 : ๊ณ„์‚ฐ๊ธฐ UI ์—ฐ๋™

  • ์•ž์„œ ๊ตฌํ˜„ํ•œ Model์„ UI์™€ ์—ฐ๋™ํ•ฉ๋‹ˆ๋‹ค.

3-1 ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ

  • ์Šคํฌ๋กค ๋ทฐ์˜ ์ฝ˜ํ…์ธ  ์˜คํ”„์…‹ ์„ค์ •์‹œ ๋ ˆ์ด์•„์›ƒ์„ ๋ฐ”๋กœ ์—…๋ฐ์ดํŠธ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค. ์ด์œ ๋Š” ๋ ˆ์ด์•„์›ƒ ์—…๋ฐ์ดํŠธ๊ฐ€ ์˜ˆ์•ฝ์ด ๋˜์–ด์žˆ๋Š” ์ƒํƒœ์—์„œ y๊ฐ’ ์ขŒํ‘œ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ์˜คํ”„์…‹์„ค์ •์„ ํ•˜๊ฒŒ๋œ๋‹ค๋ฉด ์—…๋ฐ์ดํŠธ ์ด์ „์˜ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ y๊ฐ’์œผ๋กœ ๊ณ„์‚ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— layoutIfNeeded() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•˜์˜€๋‹ค.
  • ๊ณ„์‚ฐ์‹์„ ์Šคํƒ๋ทฐ์— ์ถ”๊ฐ€ํ•  ๋•Œ ์†์„ฑ๊ฐ’์„ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•ด์ค˜์•ผํ•˜๋Š”์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค. ๊ธฐ์กด ์Šคํ† ๋ฆฌ๋ณด๋“œ์— ์„ค์ •๋˜์–ด์žˆ๋Š” ์Šคํƒ๋ทฐ์˜ ์†์„ฑ๊ฐ’๊ณผ ๋™์ผํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค.
  • ํ”„๋กœ์ ํŠธ ์š”๊ตฌ์‚ฌํ•ญ ์™ธ ์ถ”๊ฐ€ ์„ค๊ณ„ํ•œ ๋ถ€๋ถ„
    • ๊ณ„์‚ฐ์ด ๋๋‚˜๊ณ  ๋‚œ ํ›„์˜ ์ƒํ™ฉ
      • ์Šคํƒ๋ทฐ์— ์ƒˆ๋กญ๊ฒŒ ์—…๋ฐ์ดํŠธํ•˜์—ฌ ์ด์–ด์„œ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋„๋ก ์ถ”๊ฐ€ ์„ค๊ณ„
    • NaN์ด ๋ฐœ์ƒํ•˜๊ณ  ๋‚œ ํ›„์˜ ์ƒํ™ฉ
      • AC, CE ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅธ ํ›„ ๊ณ„์‚ฐ์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„
    • ์ฒซ๋ฒˆ์งธ ๊ณ„์‚ฐ์‹์ด ์˜ฌ๋ผ๊ฐˆ ๋•Œ์˜ ์ƒํ™ฉ
      • ํ”ผ์—ฐ์‚ฐ์ž๋งŒ ์˜ฌ๋ผ๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„
  • ๊ณ„์‚ฐ์ด ๋๋‚˜๊ณ ๋‚˜์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์™ธ ํ•ธ๋“ค๋ง
    • '=' ์—ฐ์‚ฐ์ž๋ฅผ ํด๋ฆญ ์‹œ ์—ฐ์‚ฐ์ž๋ฒ„ํŠผ ํ˜น์€ AC, CE ๋ฒ„ํŠผ์„ ์ œ์™ธํ•˜๊ณ  ๋‚˜๋จธ์ง€ ๋ฒ„ํŠผ๋“ค์€ ๋™์ž‘ํ•˜์ง€ ์•Š๋„๋ก ๊ตฌ์„ฑ
    • NumberFormatter๋กœ ์ธํ•ด ์‰ผํ‘œ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด์žˆ๋Š” ๋ฌธ์ž์—ด์„ replacingOccurrences๋ฅผ ์ด์šฉํ•˜์—ฌ ์ œ๊ฑฐํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„
    • ๊ณ„์‚ฐ์ด ๋˜์—ˆ๋Š”์ง€ ์•ˆ๋˜์—ˆ๋Š”์ง€ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ”„๋กœํผํ‹ฐ(hasCalculated)๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋‹ค์–‘ํ•˜๊ฒŒ ํ™œ์šฉ.
  • ์ฝ”๋“œ ๋‚ด๋ถ€ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ๊ณ ๋ฏผํ–ˆ๋˜ ๊ฒƒ
    • ViewController๋ฅผ extension์„ ํ™œ์šฉํ•˜์—ฌ ๋ถ„๋ฆฌํ•ด๋ณด์•˜๋‹ค. ์ฃผ์„์˜ˆ์•ฝ์–ด // MARK: ๋„ ๊ฐ™์ด ํ™œ์šฉํ•ด๋ณด์•˜๋‹ค.
    • ๊ณ„์† ์˜ต์…”๋„ ๋ฐ”์ธ๋”ฉ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ Label.text๋Š” ์—ฐ์‚ฐํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ฝ”๋“œ ๋‚ด๋ถ€๋ฅผ ๊ฐœ์„ ํ•ด๋ณด์•˜๋‹ค.
    • ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด += ์—ฐ์‚ฐ์ž ์‚ฌ์šฉ์„ ํ•˜์ง€์•Š์•˜๋‹ค. ํ’€์–ด์„œ ์“ฐ๋Š”๊ฒŒ ์ข€๋” ๊ฐ€๋…์„ฑ์ด ์ข‹์„ ๋•Œ๊ฐ€ ์žˆ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.
    • StackView ๋‚ด๋ถ€์— ์žˆ๋Š” UILabel์˜ text๋ฅผ joinedํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ UIStackView๋ฅผ extensionํ•˜์—ฌ ํ”„๋กœํผํ‹ฐ(toString)๋กœ ๋งŒ๋“ค์–ด์ฃผ์—ˆ๋‹ค. ์‚ฌ์šฉํ•˜๋ฉด stackView.toString ์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๊ฐ€ ๋˜์„œ ์ข€๋” ์ง๊ด€์ ์ผ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•ด์ฃผ์—ˆ๋‹ค.
    • ์ค‘๋ณต, ๋ฐ˜๋ณต๋˜๋Š” ๋ถ€๋ถ„์€ ๋ฉ”์†Œ๋“œ๋กœ ๋ถ„๋ฆฌํ•ด์ฃผ๋Š” ๋ฆฌํŒฉํ† ๋ง์„ ์ง„ํ–‰ํ–ˆ๋‹ค.
    • ์กฐ๊ฑด๋ฌธ์„ ๋ณ€์ˆ˜๋กœ ๋งŒ๋“ค์–ด์ฃผ์–ด ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€ ๊ฐ€๋…์„ฑ์„ ํ–ฅ์ƒ์‹œ์ผฐ๋‹ค.

3-2 ์˜๋ฌธ์ 

  • Stack View์˜ subview๋“ค์„ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐฉ๋ฒ•์€ ๋ฐ˜๋ณต๋ฌธ ๋ฐ–์— ์—†๋Š”๊ฑธ๊นŒ?
  • NumberFormatter์—๋Š” string์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋ฉ”์†Œ๋“œ๋„ ์žˆ์ง€๋งŒ NSNumber๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋ฉ”์†Œ๋“œ๋„ ์žˆ๋Š”๋ฐ.. ๊ผญ ์‚ฌ์šฉํ•ด์•ผํ• ๊นŒ?

3-3 Trouble Shooting

1. ์ž๋™ ์Šคํฌ๋กค ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ

  • ์ƒํ™ฉ

    • ์Šคํฌ๋กค ๋ทฐ์˜ ์ฝ˜ํ…์ธ  ๋ทฐ ์›์ ์„ ์„ค์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•ด๋ณด์•˜๋‹ค.
    let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
    scrollView.setContentOffset(bottomOffset, animated: false)
    • ๊ทธ๋Ÿฌ๋‚˜ ์Šคํฌ๋กค ๋ฐ”๊ฐ€ ์ƒ๊ธธ๋•Œ ์•ฝ๊ฐ„ ์›€์ง์ด๋ฉด์„œ ์Šคํฌ๋กค์ด ์•ˆ๋˜๋Š”... ์ด์ƒํ•ด๋ณด์ด๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ์ทจํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

    https://i.imgur.com/v4OYFOe.gif

    • ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๊ธฐ ์œ„ํ•ด์„œ 1์ฐจ์ ์œผ๋กœ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด ์ฐพ์•„๋ณด์•˜๊ณ , ์ฐพ๋Š”๋ฐ ์–ด๋ ค์›€์ด ์žˆ์–ด 3๊ธฐ ์บ ํผ ์„ ๋ฐฐ๋ถ„๋“ค์—๊ฒŒ๋„ ์งˆ๋ฌธํ•ด๋ณด์•˜์ง€๋งŒ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค.
  • ์ด์œ 

    • 3๊ธฐ ์บ ํผ ์ˆ˜๋ฐ•์˜ ๋„์›€์œผ๋กœ LLDB๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ฒ˜์Œ y์ขŒํ‘œ๊ฐ€ ์–ด๋–ค ๊ฐ’์œผ๋กœ ์ฐํžˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์•˜์œผ๋‚˜, StackView๊ฐ€ ์ถ”๊ฐ€๋˜๊ณ  ๋‚œ ํ›„ ์—…๋ฐ์ดํŠธ ๋˜์–ด y๊ฐ’ ์ขŒํ‘œ๊ฐ€ ๊ณ„์‚ฐ์ด ๋˜์–ด์•ผ ํ•˜๋Š”๋ฐ, ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ธฐ ์ด์ „์˜ y์ขŒํ‘œ๊ฐ€ ์ฐํžˆ๋Š” ๊ฒƒ์ด ํ™•์ธ๋˜์—ˆ๋‹ค.
    • ํƒ€์ด๋จธ๋‚˜ ๋น„๋™๊ธฐ์ ์œผ๋กœ ํ•ด๋‹น ๋ถ€๋ถ„์„ ํ•ด๊ฒฐํ•ด๋ณด๋ ค๊ณ  ํ•ด๋ณด์•˜์œผ๋‚˜ ๋ฐœ๋งŒ ๋‹ด๊ถˆ๋ดค์ง€ ์ œ๋Œ€๋กœ ๋ฐฐ์›Œ๋ณด์ง€ ์•Š์€ ์ง€์‹์ด๋ผ ํ•ด๊ฒฐํ•˜๋Š”๋ฐ ๋งŽ์€ ์–ด๋ ค์›€์ด ์žˆ์—ˆ๋‹ค.
    • ์ดํ›„ ์„œํฌํ„ฐ์ฆˆ Wody์—๊ฒŒ ์งˆ๋ฌธํ•ด๋ณด์•˜๊ณ  ์–ผ๋งˆ ์ง€๋‚˜์ง€ ์•Š์•„ ํ•ด๊ฒฐ์„ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ์ •์ƒ์ ์œผ๋กœ ํ•˜๋‹จ์œผ๋กœ ์ž๋™ ์Šคํฌ๋กค์ด ๋˜๋Š” ๋ชจ์Šต

https://i.imgur.com/uUW8GWB.gif

  • layoutIfNeeded()๋ผ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. (๋„์›€์„ ์ฃผ์‹  ๊ฐ“wody์—๊ฒŒ ๊ฐ์‚ฌ์˜ ์ธ์‚ฌ๋ฅผ ๋“œ๋ฆฝ๋‹ˆ๋‹ค.) ์ด ๋ฉ”์†Œ๋“œ๋Š” setNeedsLayout()๊ณผ ๊ฐ™์ด ์ˆ˜๋™์œผ๋กœ layoutSubviews๋ฅผ ์˜ˆ์•ฝํ•˜๋Š” ํ–‰์œ„์ด์ง€๋งŒ ํ•ด๋‹น ์˜ˆ์•ฝ์„ ๋ฐ”๋กœ ์‹คํ–‰์‹œํ‚ค๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์ž‘๋™ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋‹ค. update cycle์ด ์˜ฌ ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ ค layoutSubviews๋ฅผ ํ˜ธ์ถœ์‹œํ‚ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๊ทธ ์ฆ‰์‹œ layoutSubviews๋ฅผ ๋ฐœ๋™์‹œํ‚ค๋Š” ๋ฉ”์†Œ๋“œ๋‹ค.
  • ๋งŒ์ผ main run loop์—์„œ ํ•˜๋‚˜์˜ View๊ฐ€ setNeedsLayout์„ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ๋‹ค์Œ layoutIfNeeded๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด layoutIfNeeded๋Š” ๊ทธ ์ฆ‰์‹œ View์˜ ๊ฐ’์ด ์žฌ๊ณ„์‚ฐ๋˜๊ณ  ํ™”๋ฉด์— ๋ฐ˜์˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— setNeedsLayout์ด ์˜ˆ์•ฝํ•œ layoutSubviews ๋ฉ”์†Œ๋“œ๋Š” update cycle์—์„œ ๋ฐ˜์˜ํ•ด์•ผํ•  ๋ณ€๊ฒฝ๋œ ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ์ด๋Ÿฌํ•œ ๋™์ž‘ ์›๋ฆฌ๋กœ layoutIfNeeded()๋Š” ๊ทธ ์ฆ‰์‹œ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.
  • ํ•ด๊ฒฐ
    • ๋”ฐ๋ผ์„œ ์Šคํฌ๋กค๋ทฐ์˜ ์›์ ์— ๋Œ€ํ•œ ์ฝ˜ํ…์ธ ๋ทฐ์˜ ์˜คํ”„์…‹ ์„ค์ •์„ ํ•ด์ฃผ๊ธฐ ์ „์— layoutIfNeeded() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ layout์„ ์—…๋ฐ์ดํŠธ ํ•˜๊ณ  setContentOffset์„ ์„ค์ •ํ•ด์ฃผ์—ˆ๋”๋‹ˆ ํ•ด๋‹น ๋ฌธ์ œ์— ๋Œ€ํ•ด์„œ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.

2. ์ปค์Šคํ…€ ๋ทฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๊ธฐ

  • ์ƒํ™ฉ ์Šคํƒ๋ทฐ > ์Šคํƒ๋ทฐ > ๋ ˆ์ด๋ธ” ๊ณ„์ธต์„ ๊ฐ€์ง„ ๋ถ€๋ถ„์—์„œ ๋ ˆ์ด๋ธ”์˜ ํ…์ŠคํŠธ๋ฅผ ๊บผ๋‚ด๋ ค๋ฉด arrangedSubviews๋ฅผ ์ด์ค‘ for๋ฌธ์„ ๋Œ๋ฉด์„œ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ๋งˆ์Œ์— ์•ˆ๋“ค์—ˆ๋‹ค.

    extension UIStackView {
        var toString: String {
            var inputValues = [String]()
                    self.arrangedSubviews.forEach{ view in
                let subview = view as? UIStackView
                subview?.arrangedSubviews.forEach{ view in
                    let label = view as? UILabel
                    guard let input = label?.text else {
                        return
                    }
                    inputValues.append(input.replacingOccurrences(of: ",", with: ""))
                }
            }
            return inputValues.joined(separator: " ")
        }
    }
  • ํ•ด๊ฒฐ๋ฐฉํ–ฅ ๋ฆฌ๋ทฐ์–ด์ธ ์—˜๋ฆผ์—๊ฒŒ ์กฐ์–ธ์„ ๊ตฌํ•ด์„œ ์Šคํƒ๋ทฐ > ์ปค์Šคํ…€๋ทฐ ๊ณ„์ธต์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ์ปค์Šคํ…€๋ทฐ ๋งŒ๋“ค๊ธฐ์— ๋„์ „ํ•ด๋ณด์•˜๋‹ค.

  • ๊ฒฐ๊ณผ

    extension UIStackView {
        var toString: String {
            var inputValues = [String]()
            self.arrangedSubviews.forEach { view in
                guard let formualStackView = view as? FormulaStackView else {
                    return
                }
                inputValues.append(contentsOf: formualStackView.element)
            }
            return inputValues.joined(separator: " ")
        }
    }
  • FormulaStackView๋ผ๋Š” ์ปค์Šคํ…€ ๋ทฐ๋ฅผ ๋งŒ๋“ค์–ด ์คŒ์œผ๋กœ์จ ์ด์ค‘ for๋ฌธ์„ ๋Œ๋˜ ๋ฌธ์ œ๋„ ํ•ด๊ฒฐ์ด ๋˜์—ˆ๊ณ , ViewController์—์„œ ์Šคํƒ๋ทฐ ๋‚ด๋ถ€์— Label์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋Š” ๋ถ€๋ถ„๋„ ์ปค์Šคํ…€๋ทฐ ๋‚ด๋ถ€์—์„œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ๋˜์—ˆ๋‹ค.

3. ์Šคํฌ๋กค ๋ฐ”๋กœ ์ธํ•ด ๋‚ด๋ถ€ Label์˜ Text๊ฐ€ ๊ฐ€๋ ค์ง€๋Š” ๋ฌธ์ œ

Untitled

  • ์ƒํ™ฉ ๊ณ„์‚ฐ๋‚ด์—ญ์ด ์Œ“์—ฌ์„œ ์Šคํฌ๋กค๋ฐ”๊ฐ€ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ๋กœ ์Šคํฌ๋กค์„ ์ง„ํ–‰ํ•  ์‹œ ๊ธ€์”จ๊ฐ€ ๊ฐ€๋ ค์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.
  • ํ•ด๊ฒฐ๋ฐฉํ–ฅ ์Šคํฌ๋กค๋ฐ”๋ฅผ ๊ฐ€๋ฆด ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†๋Š”์ง€ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด์„œ ์ฐพ์•„๋ณด์•˜๋‹ค.
  • ๊ฒฐ๊ณผ
  • ์ฐพ์•„๋ณด๋‹ˆ ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”์—์„œ๋„ ์„ค์ •์„ ํ•ด์ค„ ์ˆ˜๋„ ์žˆ๊ณ  ์ฝ”๋“œ๋กœ๋„ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.
    • ์ฝ”๋“œ๋กœ ์„ค์ •ํ•˜๊ธฐ

      scrollView.showsHorizontalScrollIndicator = false
      scrollView.showsVerticalScrollIndicator = false
      • ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”์—์„œ ์—†์• ๊ธฐ

      https://i.imgur.com/rOkoBw3.png

      ์œ„ ์‚ฌ์ง„์—์„œ ์ฒดํฌ๋ฅผ ํ’€์–ด์ฃผ๋ฉด ๋œ๋‹ค.

4. ๋ฒ„ํŠผ์˜ ๋ชจ์–‘์„ ๋‘ฅ๊ธ€๊ฒŒ ๋งŒ๋“ค๊ธฐ

์ƒํ™ฉ ์—˜๋ฆผ์—๊ฒŒ ๋ฒ„ํŠผ์„ ๋‘ฅ๊ธ€๊ฒŒ ๋งŒ๋“ค์–ด๋ณด๋Š” ๋„์ „๊ณผ์ œ๋ฅผ ๋ฐ›๊ฒŒ๋˜์–ด ํ•ด๊ฒฐํ•ด๋ณด๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

์‹œ๋„-1 ์ฒ˜์Œ์—๋Š” ๋ฒ„ํŠผ ์ž์ฒด๊ฐ€ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ์ƒ์„ฑ๋œ ๋ฒ„ํŠผ์ด๋ผ์„œ ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”๋กœ ํ•ด๊ฒฐํ•ด๋ณด๊ณ ์ž ํ•˜์˜€๋‹ค.

    extension UIView {
        @IBInspectable var cornerRadius: CGFloat {
            get {
                return layer.cornerRadius
            }
            set {
                layer.cornerRadius = newValue
                layer.masksToBounds = newValue > 0
            }
        }
    }
  • ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋ฒ„ํŠผ์˜ cornerRadius๋ฅผ ์ง์ ‘ ๋Œ€์ž…ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์— ๋””๋ฐ”์ด์Šค๊ฐ€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์–ป๊ธฐ์—๋Š” ํž˜๋“ค๋‹ค๊ณ  ํŒ๋‹จ๋˜์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ฝ”๋“œ๋กœ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„ ํ•ด๊ฒฐํ•ด๋ณด์•˜๋‹ค.

์‹œ๋„-2

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        calculatorButtons.forEach { button in
            button.layer.cornerRadius = button.layer.frame.size.width / 2
        }
    }
  • ๋ฒ„ํŠผ์˜ ๋„ˆ๋น„ / 2๋ฅผ ํ•ด์„œ cornerRadius๋ฅผ ์„ค์ •ํ•ด์ค€ ์ฝ”๋“œ๋‹ค. ์ด๋•Œ viewWillLayoutSubviews ๋ฉ”์†Œ๋“œ๋ฅผ ์จ์ค€๋‹ค.

viewWillLayoutSubviews()

  • ๋ทฐ์˜ ๋ฐ”์šด๋“œ๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ ๊ฒฐ์ •๋˜๋Š” ์ตœ์ดˆ ์‹œ์ 
  • ์ œ์•ฝ์ด๋‚˜ ์˜คํ† ๋ ˆ์ด์•„์›ƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์„œ๋ธŒ๋ทฐ์˜ ๋ ˆ์ด์•„์›ƒ์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์ ํ•ฉํ•œ ์‹œ์ ์ด๋‹ค.
  • ์—ฌ๋Ÿฌ๋ฒˆ ์ค‘๋ณต์œผ๋กœ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค.
    • ๋ฉ”์ธ๋ทฐ์˜ ์„œ๋ธŒ๋ทฐ๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๊ฒฝ์šฐ
  • ๋ฉ”์†Œ๋“œ๋ฅผ ์•Œ์•„๋ณด๊ณ  ์—˜๋ฆผ์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ  ๋‹ค์‹œ ๋””๋ฒ„๊น…์„ ํ•ด๋ณด๋‹ˆ ๋ฒ„ํŠผ์ด ํด๋ฆญ์ด ๋˜๋Š” ์‹œ์ ๋งˆ๋‹ค ํ•ด๋‹น ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ์ด ๋˜๊ณ ์žˆ์—ˆ๋‹ค. cornerRadius๋ฅผ ์žก์•„์ฃผ๋Š” for๋ฌธ์ด ๋ฒ„ํŠผ์ด ๋ˆ„๋ฅผ๋•Œ๋งˆ๋‹ค ์‹คํ–‰๋˜๊ณ  ์žˆ์—ˆ๋˜ ๊ฒƒ์ด๋‹ค. ์ฆ‰ SubView์˜ ๋ ˆ์ด์•„์›ƒ์„ ์žก์•„์ฃผ๊ธฐ์—๋Š” ์ ์ ˆ์น˜ ๋ชปํ•œ ๋ฉ”์†Œ๋“œ์˜€๋‹ค.

์‹œ๋„-3, ๊ทธ๋ฆฌ๊ณ  ํ•ด๊ฒฐ

  • ๋ฒ„ํŠผ์˜ IBOutlet์— didSet์„ ์ค„ ์ˆ˜๋„ ์žˆ์—ˆ์ง€๋งŒ ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฌธ์ œ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๋ฐฉ๋ฒ•์€ ๋ถˆ๊ฐ€๋Šฅ ํ–ˆ๋‹ค.

  • ๋””๋ฒ„๊น…์„ ํ•ด๋ณด๋‹ˆ viewWillLayoutSubviews ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— ๋ ˆ์ด์•„์›ƒ์ด ๊ฐฑ์‹ ๋˜์–ด ๋ฒ„ํŠผ์˜ ๋„ˆ๋น„๊ฐ€ ๋ฐ”๋€Œ๊ณ  ์žˆ์—ˆ๋‹ค. (๋””๋ฐ”์ด์Šค๋Š” ์•„์ดํฐ SE ๊ธฐ์ค€์ด๋‹ค. SE ์ด์ƒ ๋””๋ฐ”์ด์Šค์—์„œ๋Š” ์—†๋˜ ๋ฌธ์ œ์˜€๋‹ค.) IBOutlet์˜ didSet์€ viewDidLoad๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ์ ์ ˆํ•˜์ง€ ๋ชปํ•œ ๋ฐฉ๋ฒ•์ด์˜€๋‹ค.

  • ๋”ฐ๋ผ์„œ ์ตœ์†Œํ•œ์œผ๋กœ ์ ๊ฒŒ ํ˜ธ์ถœ๋˜๋Š” updateViewConstraints๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

    func setupButtons() {
        calculatorButtons.forEach { button in
            button.layoutIfNeeded()
            button.layer.cornerRadius = button.layer.bounds.width / 2
        }
    }
    
    override func updateViewConstraints() {
        super.updateViewConstraints()
        setupButtons()
    }
  • updateViewConstraints์— ๋ฒ„ํŠผ์…‹ํŒ… ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ ์žˆ๊ณ , for๋ฌธ ๋‚ด๋ถ€์—์„œ ๋ฒ„ํŠผ๋งˆ๋‹ค layoutIfNeeded๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ์„ ๊ฐฑ์‹ ํ•˜๊ณ  ์ดํ›„ cornerRadius ๊ฐ’์„ ๋Œ€์ž…ํ•ด์ฃผ๊ณ ์žˆ๋‹ค.

  • ๋ ˆ์ด์•„์›ƒ์„ ๊ฐฑ์‹ ํ•˜๋Š” ์ด์œ ๋Š” ๊ฐฑ์‹ ํ•˜์ง€ ์•Š์œผ๋ฉด ์œ„ ๋””๋ฒ„๊น…์‹œ ๋ฐœ๊ฒฌํ•˜์˜€๋˜ ์ตœ์ข… ๋ ˆ์ด์•„์›ƒ์ด ์•„๋‹ˆ๋ผ ์ž„์˜๋กœ ์žกํ˜€์žˆ๋˜ frame๊ฐ’์œผ๋กœ ๊ณ„์‚ฐ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์ฒ˜๋Ÿผ ์ฐŒ๊ทธ๋Ÿฌ์ง„ ์›์ด ๋‚˜์˜จ๋‹ค.

๊ฒฐ๋ก 

  • viewDidLoad์—์„œ frame์‚ฌ์ด์ฆˆ๊ฐ€ ์ •ํ™•ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ๋ทฐ๋Š” ๋กœ๋“œ๋๋‹ค๊ณ  ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋ฐฐ์น˜๊ฐ€ ๋๋‹ค๊ณ  ํ• ์ˆ˜๋Š” ์—†๋‹ค. ๋”ฐ๋ผ์„œ ์œ„์™€ ๊ฐ™์€ ํ˜„์ƒ์€ viewDidLoad์—์„œ ์ž„์˜๋กœ ์žกํ˜”๋˜ frame๊ฐ’์ด viewWillLayoutSubviews๊ฐ€ ํ˜ธ์ถœํ•˜๋ฉด์„œ ํ•˜์œ„ ๋ทฐ๊ฐ€ ๋ฐฐ์น˜๋˜๊ณ  ์ดํ›„ ๊ฐ’์ด ๋ณ€ํ–ˆ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๊ฒ ๋‹ค. ๋”ฐ๋ผ์„œ ํ•˜์œ„๋ทฐ๊ฐ€ ๋ฐฐ์น˜๊ฐ€ ๋˜๊ณ ๋‚˜์„œ ๋ฒ„ํŠผ์˜ ๋ ˆ์ด์•„์›ƒ์„ ์žก์•„์ค˜์•ผ ํ•ด๊ฒฐ์ด ๊ฐ€๋Šฅํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค.

์—ฌ๊ธฐ์„œ ์˜๋ฌธ์ ์ด ๋“œ๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ ๋””๋ฐ”์ด์Šค๋“ค์€ ์ƒ๊ด€์—†๋Š”๋ฐ ์™œ SE์—์„œ๋งŒ ๋ฒ„ํŠผ์˜ ํฌ๊ธฐ๊ฐ€ ์ค„์–ด๋“œ๋Š” ๊ฒƒ์ผ๊นŒ?

  • 3๊ธฐ ์บ ํผ ์ˆ˜๋ฐ• ์˜ ๋„์›€์œผ๋กœ ํ•ด๋‹น ์˜๋ฌธ์ ์„ ํ’€ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

https://i.imgur.com/MiyseWl.png

  • HIG์—์„œ ์žฅ์น˜๋“ค์˜ ์น˜์ˆ˜๋ฅผ ํ™•์ธํ•ด์„œ ์„ธ๋กœ๋ฅผ ๋ณด๋ฉด 200~300์ •๋„ ์ฐจ์ด๊ฐ€ ๋‚˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์ง„์—์„œ๋„ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ์„ธ๋กœ ํฌ๊ธฐ๊ฐ€ ์—„์ฒญ ์ฐจ์ด๋‚œ๋‹ค. ๋”ฐ๋ผ์„œ ์ž‘์•„์ง„ ๋””๋ฐ”์ด์Šค์— ์˜คํ†  ๋ ˆ์ด์•„์›ƒ์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด ๋ฒ„ํŠผ์˜ ํฌ๊ธฐ๋ฅผ ์ค„์ผ ์ˆ˜ ๋ฐ–์— ์—†๋‹ค๋Š” ์ถ”์ธก์ด ๊ฐ€๋Šฅํ•ด์กŒ๋‹ค.
  • ์ด๋Ÿฌํ•œ ์‚ฌ์‹ค์„ ์ฆ๋ช…ํ•ด๋‚ผ ์ˆ˜๋„ ์žˆ๋‹ค. ์ง์ ‘ ๋ ˆ์ด์•„์›ƒ์„ ๋‹ค ๊ณ„์‚ฐํ•˜์—ฌ ์น˜์ˆ˜์™€ ๋งž๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ... ๋‚˜์ค‘์— ์‹œ๋„ํ•ด๋ด์•ผ๊ฒ ๋‹ค. ๐Ÿ˜‡

๐Ÿคฉย ์ˆ˜๋ฐ•์—๊ฒŒ ๋‹ต๋ณ€๋ฐ›๋Š” ์™€์ค‘์— ๋ฐ›์•˜๋˜ ์กฐ์–ธ

  • didSet์œผ๋กœ UI ์š”์†Œ๋“ค์˜ ๋ ˆ์ด์•„์›ƒ์„ ์žก์•„์ฃผ๋Š”๊ฑด ๋ถ€์ž์—ฐ์Šค๋Ÿฝ๋‹ค. ์˜คํžˆ๋ ค ์ง€๊ธˆ์ฒ˜๋Ÿผ view๊ฐ€ ๋ฐฐ์น˜๋œ ํ›„ ๋ ˆ์ด์•„์›ƒ์„ ์žก์•„์ค€ ๊ฒƒ์ด ์ž์—ฐ์Šค๋Ÿฝ๊ณ  ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  UI ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ• ๋•Œ ํด๋กœ์ €๋กœ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๊ณ , ์ธ์Šคํ„ด์Šค๋กœ ์„ ์–ธ ์ดํ›„ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์ค„ ์ˆ˜๋„ ์žˆ๋‹ค.
  • ์„ ์–ธ ์ดํ›„ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌธ๋งฅ์ƒ ๋ถ€์ž์—ฐ์Šค๋Ÿฌ์šธ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ง€์–‘ํ•˜๋Š”๊ฒŒ ์ข‹์€ ๊ฒƒ ๊ฐ™๋‹ค๋Š” ์˜๊ฒฌ.
    • let์œผ๋กœ ์„ ์–ธํ›„ ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด์ฃผ๋Š” ๊ฑฐ๋‹ˆ๊นŒ ๋ถ€์ž์—ฐ์Šค๋Ÿฝ๋‹ค๋Š” ๋Šฌ์•™์Šค!
    • ์• ์ดˆ์— ํด๋กœ์ €๋กœ ์„ ์–ธํ•˜์—ฌ ์š”์†Œ์˜ ์†์„ฑ๋“ค์„ ์„ค์ •ํ•ด์ฃผ๊ณ  ๊ทธ๋Œ€๋กœ ์ญ‰ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ๋” ์ž์—ฐ์Šค๋Ÿฝ๋‹ค!

3-4 ๋ฐฐ์šด ๊ฐœ๋…

  • ์ฝ”๋“œ๋กœ UI๋ฅผ ๊ทธ๋ ค๋ณด๋Š” ๋ฐฉ๋ฒ•
  • Stack View
    • ์ฝ”๋“œ๋กœ Stack View์˜ layout์„ ์žก๋Š” ๋ฐฉ๋ฒ•
  • Scroll View
    • ์Šคํฌ๋กค ๋ฐ” ์—†์• ๋Š” ๋ฐฉ๋ฒ•
  • layoutIfNeeded()ํ™œ์šฉ
  • NumberFormatter
  • LLDB
  • super.viewDidLoad()
  • protocol LocalizedError ์šฉ๋„
  • @IBInspectable
  • viewWillLayoutSubviews()
  • ์ปค์Šคํ…€๋ทฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• (only Code)
    • init(frame:)์™€ย init(coder:)์˜ ์ฐจ์ด์ 
  • View Life Cycle์˜ ๋Œ€ํ•œ ๊นŠ์€ ์ดํ•ด
  • frame๊ณผ bounds์˜ ์ฐจ์ด์ 
  • IBOutlet์˜ didSet์€ ์–ธ์ œ trigger๋˜๋Š”์ง€?

3-5 PR ํ›„ ๊ฐœ์„ ์‚ฌํ•ญ

  • ๋™์ผํ•œ return์„ ํ•˜๋Š” guard๋ฌธ์„ ํ•ฉ์ณ์„œ ๊ฐœ์„ 
  • ์Šคํฌ๋กค๋ฐ” ๋•Œ๋ฌธ์— ๊ฐ€๋ ค์ง€๋Š” ๋ฌธ์ œ ํ•ด๊ฒฐ
  • ์ฃผ์„์œ„์น˜์™€ ์ค„๋ฐ”๊ฟˆ์œผ๋กœ ์ฝ”๋“œ ๋‚ด๋ถ€ ๊ฐ€๋…์„ฑ ๊ฐœ์„ 
  • ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„ ๋ฉ”์†Œ๋“œ๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ฐœ์„ 
  • toggle ์‚ฌ์šฉ์œผ๋กœ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๋ถ€๋ถ„์„ ์ง์ ‘ ๋Œ€์ž…ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ฐœ์„ 
  • LocalizedError ํ”„๋กœํ† ์ฝœ์„ ํ™œ์šฉํ•˜์—ฌ description์„ ์ข€ ๋” ์ง๊ด€์ ์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ฐœ์„ 
  • ์ปค์Šคํ…€ ๋ทฐ๋ฅผ ๋งŒ๋“ค์–ด์„œ ViewController ๋‚ด๋ถ€ ์ฝ”๋“œ ๊ฐœ์„ 

top

About

๐Ÿงฎ ์•„์ดํฐ์˜ ๊ธฐ๋ณธ์•ฑ์ธ ๊ณ„์‚ฐ๊ธฐ ์•ฑ๊ณผ ํก์‚ฌํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ ์•ฑ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages

  • Swift 100.0%