Skip to content

๐Ÿ‡ซ๐Ÿ‡ท ํ…Œ์ด๋ธ”๋ทฐ๋ฅผ ํ™œ์šฉํ•œ ๋‹ค์–‘ํ•œ ๊ตญ๊ฐ€์˜ ๋ฌธํ™”์œ ์‚ฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ์•ฑ

Notifications You must be signed in to change notification settings

leeari95/ios-exposition-universelle

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

59 Commits
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ‡ซ๐Ÿ‡ท ๋งŒ๊ตญ๋ฐ•๋žŒํšŒ ํ”„๋กœ์ ํŠธ

  • ํŒ€ ํ”„๋กœ์ ํŠธ(2์ธ)
  • ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„: 2021.12.06 ~ 2021.12.17

๋ชฉ์ฐจ

ํ‚ค์›Œ๋“œ

  • JSON Codable Decodable Encodable
  • MVC
  • TableView
    • Cell Reuse
    • TableView Delegate, DataSource
    • TableView register
    • xib
  • NSMutableAttributedString
  • Result
  • Auto Layout
  • ImageVIew
  • Navigation Controller
    • Orientations
  • Accessibility
    • Dynamic Type
    • Voice over
  • static
  • UIButton Configuration

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

UITableView, JSON์„ ํ™œ์šฉํ•œ ์•ฑ์ด์—์š”.

๋‹ค์–‘ํ•œ ๊ตญ๊ฐ€์˜ ๋ฌธํ™”์œ ์‚ฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์–ด์š” ! ๐ŸŒŽ


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

๐Ÿ” ๋ฆฌ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ๋ฌธํ™”์œ ์‚ฐ๋“ค์˜ ์„ค๋ช…์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿ“ฑ ์ถœํ’ˆ์ž‘์„ ๊ตฌ๊ฒฝํ•  ๋•Œ์—๋Š” ๊ฐ€๋กœ๋ชจ๋“œ๋ฅผ ์ง€์›ํ•ด์š”!

โœจ ์ฒซํ™”๋ฉด์€ ์„ธ๋กœ๋ชจ๋“œ ๊ณ ์ • ๋ฐ ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๊ฐ€ ์ˆจ์–ด์žˆ๋Š” ํŠน์ง•์ด ์žˆ์–ด์š”.

๐Ÿ‘€ ์ ‘๊ทผ์„ฑ์„ ์œ„ํ•ด ๋””๋ฐ”์ด์Šค์˜ ๊ธ€์ž ํฌ๊ธฐ ์„ค์ •์— ๋”ฐ๋ผ ์•ฑ์˜ ๊ธ€์žํฌ๊ธฐ๋„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ ์šฉ๋˜์š”!


๐Ÿ›  Trouble Shooting

"๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ํŠน์ • ViewController์—์„œ๋งŒ ์ˆจ๊น€ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด?"

  • ์ƒํ™ฉ MainViewController๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๋ทฐ๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ฆ‰ MainViewController๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ์ˆจ๊น€์ฒ˜๋ฆฌ ํ•ด์•ผ ํ•œ๋‹ค.

  • ์‹œ๋„ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ๊ฐ์ถ”๊ธฐ

    • ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํด๋ฆญ ํ›„
    • ์šฐ์ธก Inspector์—์„œ Shows Navigation Bar ์ฒดํฌ๋ฅผ ํ•ด์ œํ•ด์ค€๋‹ค.
    • https://camo.githubusercontent.com/8ee13833a1e08e99b2f1c058d511eb599201481275636a037336211633154760/68747470733a2f2f692e696d6775722e636f6d2f386a70416d31772e706e67
  • ์ฝ”๋“œ๋กœ ๊ฐ์ถ”๊ธฐ

    • ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋กœ Embed In ๋˜์–ด์žˆ๋Š” ViewController ๋‚ด๋ถ€์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.
      • self.navigationController?.isNavigationBarHidden = true
  • ์ด์œ  ์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์€ Navigation Controller์— ์—ฐ๊ฒฐ๋˜์–ด์žˆ๋Š” ๋ชจ๋“  ViewController์˜ Navigation Bar๊ฐ€ ์ˆจ๊ฒจ์ง„๋‹ค.

  • ํŠน์ • ViewController์˜ Navigation Bar๋ฅผ ์ˆจ๊ธฐ๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

  • ํ•ด๊ฒฐ ํ•ด๋‹น ๋ฐฉ๋ฒ•์€ View Life Cycle ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ทฐ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ผ ๋•Œ Navigation Bar๋ฅผ ์ˆจ๊ธฐ๊ณ  ๋‹ค๋ฅธ์ฐฝ์œผ๋กœ ๋„˜์–ด๊ฐˆ๋•Œ ๋‹ค์‹œ ๋ณด์ด๊ฒŒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
}

"์…€์ด Select ๋˜์—ˆ์„ ๋•Œ ์‚ฌ๋ผ์ง€์ง€ ์•Š๋Š” ํšŒ์ƒ‰๋ฐฐ๊ฒฝ"

  • ์ƒํ™ฉ ์…€์„ ํด๋ฆญํ•ด์„œ ํ™”๋ฉด์ „ํ™˜ํ›„ ๋‹ค์‹œ ๋Œ์•„์™€๋„ ์…€์˜ ๋ฐฐ๊ฒฝ์ƒ‰์ด ์•ˆ์—†์–ด์ง€๋Š” ํ˜„์ƒ์ด ์ผ์–ด๋‚ฌ๋‹ค.

  • ์ด์œ  ํ…Œ์ด๋ธ”๋ทฐ์˜ ์…€์ด ์„ ํƒ๋˜๋ฉด ํšŒ์ƒ‰์œผ๋กœ ๋ณ€ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ๋ฌธ์ œ๋Š” ์ด๋ ‡๊ฒŒ ๋ณ€ํ•œ ์ƒ‰์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋œ๋‹ค.

  • ํ•ด๊ฒฐ ํ…Œ์ด๋ธ” ๋ทฐ์˜ ์…€์„ ์„ ํƒํ•˜๋ฉด ํšŒ์ƒ‰์œผ๋กœ ๋ณ€ํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์›๋ž˜ ์ƒ‰์œผ๋กœ ๋ฐ”๋กœ ๋Œ์•„์˜ค๊ฒŒ ํ•˜๋ ค๋ฉด ์•„๋ž˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์…€์˜ ํ„ฐ์น˜๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ์„ ๋•Œ, deselect๋˜๋„๋ก ํ•˜๋ฉด ๋œ๋‹ค.

    extension ItemListViewController: UITableViewDelegate {
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
        }
    }
  • ์ ์šฉํ›„

"ํ™”๋ฉด ์ „ํ™˜ ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•"

  • ๋ฆฌ์ŠคํŠธ์—์„œ ์ƒ์„ธ๋ณด๊ธฐ๋กœ ํ™”๋ฉด์ „ํ™˜์ด ๋  ๋•Œ ํ•ด๋‹น ์…€์— ํ•ด๋‹นํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์Œ ํ™”๋ฉด์œผ๋กœ ๋„˜๊ฒจ์ฃผ๊ธฐ ์œ„ํ•ด ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•๋“ค์„ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
  • 1 performSegue์‹œ sender๋ฅผ nil์ด ์•„๋‹ˆ๋ผ ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ›„ prepare์‹œ sender๋ฅผ ๋‹ค์šด์บ์ŠคํŒ…์„ ํ™œ์šฉํ•˜์—ฌ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
extension ItemListViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "ItemDetailView", sender: items[indexPath.row])
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let item = sender as? ExpositionItem,
          let nextViewController = segue.destination as? ItemDetailViewController else {
          return
      }
    nextViewController.item = item
}
  • 2 prepare ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์—์„œ ์„ ํƒ๋œ ์…€์˜ indexPath๋ฅผ ๊ตฌํ•ด์„œ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์กด์žฌํ•œ๋‹ค.
extension ItemListViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "ItemDetailView", sender: nil)
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let indexPath = itemListTableVIew.indexPathForSelectedRow,
          let nextViewController = segue.destination as? ItemDetailViewController else {
        return
    }
    nextViewController.item = items[indexPath.row]
}

"attributedText๋ฅผ ์ ์šฉํ•ด์ค€ Label์˜ Dynamic Type ์ ์šฉํ•˜๊ธฐ"

  • ์ƒํ™ฉ ๋ถ€๋ถ„์ ์œผ๋กœ ํ…์ŠคํŠธ ํฌ๊ธฐ ํŽธ์ง‘ํ•ด์ค€ ๊ธ€์ž๋“ค์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ Dynamic Type์ด ์ ์šฉ์ด ์•ˆ๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ๋‹ค.
  • ์ด์œ  ์•Œ๊ณ ๋ณด๋‹ˆ ํŽธ์ง‘ํ•ด์ค€ ๋ถ€๋ถ„(prefix)์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๊ธ€์ž์˜ ํฐํŠธ๋„ ํฌ๊ธฐ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค์ด๋‚˜๋ฏน ํƒ€์ž…๋„ ๊ฐ™์ด ์ ์šฉํ•ด์ค˜์•ผ ๋ฌ๋‹ค.
    • ๋งจ ์ฒ˜์Œ ๊ธ€์ž์˜ TextStyle์ด title3๋กœ ์„ค์ •๋˜์–ด์žˆ๋Š”๋ฐ addAttribute๋ฅผ ํ•˜๋Š” ์ˆœ๊ฐ„ TextStyle์ด ํ’€๋ฆฌ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
  • ํ•ด๊ฒฐ ๋”ฐ๋ผ์„œ ๋‚˜๋จธ์ง€ ํ…์ŠคํŠธ์— ๋Œ€ํ•ด์„œ๋„ TextStyle์„ ์ง€์ •ํ•ด์ค€ ํ›„ addAttribute ํ•ด์ฃผ๋‹ˆ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.

"๋ฉ”์ธ์˜ ํ•˜๋‹จ ๋ฒ„ํŠผ์ด ์œ„ Label๊ณผ ๊ฒน์ณ๋ณด์ด๋Š” ํ˜„์ƒ"

  • ์ƒํ™ฉ Dynamic Type์„ ์ตœ๋Œ€ํ•œ ๋Š˜๋ ธ์„ ๋•Œ ํ•˜๋‹จ์˜ ๋ฒ„ํŠผ titleLabel์ด ์ปค์กŒ์ง€๋งŒ ์ด์— ๋”ฐ๋ผ StackView์˜ ๋†’์ด๊ฐ€ ๋Š˜์–ด๋‚˜์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ๋‚˜ํƒ€๋‚ฌ๋‹ค.

  • ์‹œ๋„1 ๋ ˆ์ด์•„์›ƒ์ด ์•ˆ์žกํ˜€ ์žˆ์–ด์„œ ๊ทธ๋Ÿฐ๊ฑด๊ฐ€ ์‹ถ์–ด์„œ ๋ฒ„ํŠผ์˜ ๋†’์ด๋ฅผ ์Šคํƒ๋ทฐ์™€ ๊ฐ™๊ฒŒ ์„ค์ •์„ ์ฃผ์—ˆ์œผ๋‚˜ ํ˜„์ƒ์€ ๋™์ผํ–ˆ๋‹ค.

  • ์‹œ๋„2 ๋˜ํ•œ StackView์˜ Alignment๋ฅผ center๋กœ ์ฃผ์—ˆ์„ ๋•Œ์—๋„ ์•ฝ๊ฐ„ ๊ฒน์ณ์ง์ด ์ค„๊ธด ํ–ˆ์ง€๋งŒ ๋™์ผํ•œ ๋ฌธ์ œ๋กœ ํ•ด๊ฒฐ์€ ๋˜์ง€ ์•Š์•˜๋‹ค.

  • ํ•ด๊ฒฐ ๋ฒ„ํŠผ์˜ Style์ด ์ด์ „์—” ๋ฒ„์ „ ํ˜ธํ™˜ ๋ฌธ์ œ๋กœ default๋กœ ๋งž์ถฐ์ ธ ์žˆ์—ˆ๋Š”๋ฐ, iOS 15๋ถ€ํ„ฐ ์ ์šฉ ๊ฐ€๋Šฅํ•œ Plain์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์ž ๋ ˆ์ด์•„์›ƒ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ด๋–ค ์ฐจ์ด๋กœ ํ•ด๋‹น ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋Š”์ง€ ์ •ํ™•ํ•œ ํŒŒ์•…์€ ์–ด๋ ค์› ๋‹ค. ๊ธฐ์กด์— Dynamic Type์ด ์ ์šฉ๋˜์ง€ ์•Š์•˜๋˜ ๋ฒ„ํŠผ์ด ์ด๋ฒˆ์— ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜๋ฉด์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ์šฉ๋˜๊ฒŒ๋” ๋ฐ”๋€Œ์—ˆ๋Š”๋ฐ ๊ทธ ๋ถ€๋ถ„ ๋•Œ๋ฌธ์ด ์•„๋‹Œ๊ฐ€ ์‹ถ๋‹ค.

"ํŠน์ • ํ™”๋ฉด๋งŒ Orientation ๊ณ ์ •"

  • ์ƒํ™ฉ ์ฒซ๋ฒˆ์งธ ๋ทฐ์ธ MainView๋งŒ Orientation์„ ๊ณ ์ • ํ•ด์ฃผ๊ณ ์‹ถ์—ˆ๋Š”๋ฐ, ์ฝ”๋“œ๋กœ ์ ์šฉ์„ ํ•ด์ฃผ๋ คํ•ด๋„ ๋ณ€ํ™”๊ฐ€ ์—†๋Š” ํ˜„์ƒ์ด ๋‚˜ํƒ€๋‚ฌ๋‹ค.
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
            return .portrait
        }
  • ์ด์œ  ์œ„ ํ”„๋กœํผํ‹ฐ๋ฅผ overrideํ•˜์—ฌ ํ™”๋ฉด ๊ณ ์ •์„ ํ•ด์ฃผ๊ณ ์‹ถ์—ˆ์ง€๋งŒ ์ ์šฉ์ด ๋˜์ง€์•Š์•˜๊ณ , ์ด์œ ๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์˜ ๋ทฐ๋“ค์˜ Hierarchy ์ƒ๋‹จ์—” NavigationController๊ฐ€ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋‹จ ๋ทฐ์˜ Orientation์ด ๊ณ ์ •๋˜์–ด์žˆ์ง€ ์•Š์•„ ํ•˜์œ„ ๋ทฐ๋“ค์˜ Orientation ๋˜ํ•œ ์ ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.
  • ํ•ด๊ฒฐ Navigation์˜ ํด๋ž˜์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์—ฌ Orientation์„ ์ ์šฉ์‹œ์ผœ์ค„๊นŒ ํ–ˆ์ง€๋งŒ, Main๋ทฐ๋งŒ ๊ณ ์ •์‹œ์ผœ์ฃผ๊ณ  ์‹ถ์—ˆ๊ธฐ๋•Œ๋ฌธ์— ๊ตณ์ด ์ƒ์„ฑ์น˜์•Š๊ณ , UINavigationControllerDelegate๋ฅผ MainViewController์— ์ฑ„ํƒํ•˜์—ฌ ๋‚ด๋ถ€ ๋ฉ”์†Œ๋“œ์ธ navigationControllerSupportedInterfaceOrientations ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ Orientation์„ ์ฒซ ํ™”๋ฉด์—์„œ๋งŒ ๊ณ ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•ด์ฃผ์—ˆ๋‹ค.
    extension MainViewController: UINavigationControllerDelegate {
        func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
            return navigationController.topViewController?.supportedInterfaceOrientations ?? .all
        }
    }

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

"ํ…Œ์ด๋ธ”๋ทฐ์˜ ์…€์˜ ์žฌ์‚ฌ์šฉ ์ดํ•ด"

iOS ๊ธฐ๊ธฐ๋Š” ํ•œ์ •๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€์ง€๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ๋™ํ•œ๋‹ค. ๋งŒ์•ฝ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ฃผ๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ๊ณ  ๋ฐ์ดํ„ฐ์˜ ์–‘ ๋งŒํผ ๋งŽ์€ ๋ทฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ํ™”๋ฉด์— ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋Š” ๋ทฐ์˜ ๊ฐœ์ˆ˜๋Š” ํ•œ์ •๋˜์–ด ์žˆ์ง€๋งŒ ํ‘œํ˜„ํ•ด์•ผํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์€ ๊ฒฝ์šฐ ๋ฐ˜๋ณต๋œ ๋ทฐ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ๋ทฐ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ž‘์•„์„œ ๋ฐ์ดํ„ฐ์˜ ์–‘๋งŒํผ ๋งŽ์€ ๋ทฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋งŽ์ด ๋‚ญ๋น„ํ•  ์ˆ˜ ๋ฐ–์— ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ทฐ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฏ€๋กœ์จ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•˜๊ณ  ์„ฑ๋Šฅ ๋˜ํ•œ ํ–ฅ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์žฌ์‚ฌ์šฉ์˜ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ

    • UITableViewCell
    • UICollectionViewCell
  • ์žฌ์‚ฌ์šฉ ์›๋ฆฌ

    • ํ…Œ์ด๋ธ”๋ทฐ ๋ฐ ์ปฌ๋ ‰์…˜ ๋ทฐ์—์„œ ์…€์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ ์†Œ์Šค์— ๋ทฐ(์…€) ์ธ์Šคํ„ด์Šค๋ฅผ ์š”์ฒญํ•œ๋‹ค.
    • ๋ฐ์ดํ„ฐ ์†Œ์Šค๋Š” ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์…€์„ ๋งŒ๋“œ๋Š” ๋Œ€์‹  ์žฌ์‚ฌ์šฉ ํ(Reuse Queue)์— ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ๋Œ€๊ธฐํ•˜๊ณ ์žˆ๋Š” ์…€์ด ์žˆ๋Š”์ง€ ํ™•์ธ ํ›„ ์žˆ์œผ๋ฉด ๊ทธ ์…€์— ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์—†์œผ๋ฉด ์ƒˆ๋กœ์šด ์…€์„ ์ƒ์„ฑํ•œ๋‹ค.
    • ํ…Œ์ด๋ธ”๋ทฐ ๋ฐ ์ปฌ๋ ‰์…˜๋ทฐ๋Š” ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ ์…€์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ํ™”๋ฉด์— ํ‘œ์‹œํ•œ๋‹ค
    • ์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กค์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์ผ๋ถ€ ์…€๋“ค์ด ํ™”๋ฉด ๋ฐ–์œผ๋กœ ์‚ฌ๋ผ์ง€๋ฉด์„œ ๋‹ค์‹œ ์žฌ์‚ฌ์šฉ ํ์— ๋“ค์–ด๊ฐ„๋‹ค.
    • ์œ„ 1๋ฒˆ๋ถ€ํ„ฐ 4๋ฒˆ๊นŒ์ง€์˜ ๊ณผ์ •์ด ๊ณ„์† ๋ฐ˜๋ณต๋œ๋‹ค.

"์„ ํƒํ•œ ์…€์˜ indexPath๋ฅผ DataSource๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์•Œ๋ ค๋ฉด?"

tableView์˜ ์†์„ฑ์ค‘ indexPathForSelectedRow ๊ฐ€ ์žˆ๋Š”๋ฐ, ์„ ํƒ๋œ row(Cell)์˜ indexPath๋ฅผ ๊ฐ€์ ธ์™€ ํ™œ์šฉํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

var indexPathForSelectedRow: IndexPath? { get }

"Label์˜ ํŠน์ • ๋ฒ”์œ„์˜ ๊ธ€์ž ํฌ๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•"

// ๋‚ด๊ฐ€ ์ ์šฉํ•˜๊ณ  ์‹ถ์€ ํฐํŠธ ์‚ฌ์ด์ฆˆ
let fontSize = let fontSize = UIFont.systemFont(ofSize: 30)

// label์— ์žˆ๋Š” Text๋ฅผ NSMutableAttributedString๋กœ ์ดˆ๊ธฐํ™”ํ•ด์ค€๋‹ค.
guard let text = label.text else {
    return
}
let attributedString = NSMutableAttributedString(string: text)

// ์œ„์—์„œ ๋งŒ๋“  attributedString์— addAttribute ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด Attribute๋ฅผ ์ ์šฉํ•ด์ค€๋‹ค.
let range = (text as NSString).range(of: prefix) // ํŽธ์ง‘ํ•˜๊ณ  ์‹ถ์€ ๊ธ€์ž์˜ ๋ฒ”์œ„๋ฅผ ๊ตฌํ•ด์ค€๋‹ค.
attributedString.addAttribute(.font, value: fontSize, range: range)

// ์ตœ์ข…์ ์œผ๋กœ ๋‚ด label์— ์†์„ฑ์„ ์ ์šฉํ•œ๋‹ค.
label.attributedText = attributedString
  • ์œ„ ๋ฐฉ๋ฒ•์„ ์ ์šฉํ•˜์—ฌ ๋งŒ๋“  ํ•จ์ˆ˜

    func editFontSize(of prefix: String ,in label: UILabel) {
        guard let text = label.text else {
            return
        }
        let fontSize = UIFont.systemFont(ofSize: label.font.pointSize + 3)
        let attributedString = NSMutableAttributedString(string: text)
        let range = (text as NSString).range(of: prefix)
        attributedString.addAttribute(.font, value: fontSize, range: range)
        label.attributedText = attributedString
    }

์‚ฌ์ด์ฆˆ ์™ธ์—๋„ ํฐํŠธ๋‚˜, ์ƒ‰์ƒ์„ ๋ถ€๋ถ„์ ์œผ๋กœ ๋ฐ”๊ฟ”์ค„ ์ˆ˜๋„ ์žˆ๋‹ค.

  • NSForegroundColorAttributeName NSStrokeColorAttributeName NSUnderlineStyleAttributeName NSBackgroundColorAttributeName NSStrikethroughStyleAttributeName

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

Storyboard Reference

  • ํŒ€์›๊ณผ ํ˜‘์—…์‹œ Git ์ถฉ๋Œ ์˜ˆ๋ฐฉ์„ ์œ„ํ•ด ์Šคํ† ๋ฆฌ๋ณด๋“œ ๊ด€๋ฆฌ๋ฅผ ์–ด๋–ป๊ฒŒ ํ• ์ง€ ๊ณ ๋ฏผํ•˜๊ณ , Storyboard Reference๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ถ„๋ฆฌํ•ด์ฃผ๊ธฐ๋กœ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. (One Storyboard, One ViewController)
  • ์Šคํ† ๋ฆฌ๋ณด๋“œ ํŒŒ์ผ ํ•œ๊ฐœ๋‹น ํ•œ๊ฐœ์˜ ViewController๋งŒ ์กด์žฌํ•˜๋ฏ€๋กœ, ํ˜‘์—… ์‹œ ๋”์ด์ƒ ๋‹ค๋ฅธ ์Šคํ† ๋ฆฌ๋ณด๋“œ๋ฅผ ๊ฑด๋“œ๋ฆฌ๋Š” ์ผ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

top

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

๋ชฉ์ฐจ


STEP 1 : ๋ชจ๋ธ ํƒ€์ž… ๊ตฌํ˜„

JSON ํฌ๋งท์˜ ๋ฐ์ดํ„ฐ์™€ ๋งค์นญํ•  ๋ชจ๋ธ ํƒ€์ž…์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

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

  • JSON ํŒŒ์ผ์„ ์‚ดํŽด๋ณด๊ณ  ์˜ˆ์‹œ ํ™”๋ฉด์„ ๋ณด๋ฉด์„œ ์–ด๋–ค ๋ถ€๋ถ„์„ ํƒ€์ž…์œผ๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ• ์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
  • JSON ๊ด€๋ จ ํƒ€์ž…์„ ์„ค๊ณ„ํ•  ๋•Œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ๋ณ€์ˆ˜๋กœ ๋งŒ๋“œ๋Š”์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
  • ํƒ€์ž…์„ ์„ค๊ณ„ํ•˜๋ฉด์„œ ๊ณ ๋ฏผํ•ด๋ณด๋‹ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๋””์ฝ”๋”ฉ๋งŒ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Codable์ด ์•„๋‹ˆ๋ผ Decodable๋งŒ ์ฑ„ํƒํ•˜๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

1-2 ์˜๋ฌธ์ 

  • ํ˜„์—…์—์„œ๋Š” JSON ๊ด€๋ จ ํƒ€์ž…์„ ์„ค๊ณ„ํ•  ๋•Œ ์‚ฌ์ดํŠธ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์„ค๊ณ„ํ•˜๊ธฐ๋„ ํ• ๊นŒ?
  • ์™œ JSON ๊ด€๋ จ ํƒ€์ž…์„ ๋งŒ๋“ค ๋•Œ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ƒ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ๋ผ ๋ณ€์ˆ˜๋กœ ๋งŒ๋“ค์ง€?

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

  • Codable์„ ์ด์šฉํ•˜์—ฌ JSON์„ ์ธ์ฝ”๋”ฉ, ๋””์ฝ”๋”ฉ ํ•˜๋Š” ๋ฐฉ๋ฒ•

top

STEP 2 : ํ™”๋ฉด ๊ตฌํ˜„

๋ฉ”์ธ ํ™”๋ฉด, ์ถœํ’ˆ์ž‘ ๋ชฉ๋ก, ์ถœํ’ˆ์ž‘ ์ƒ์„ธํ™”๋ฉด์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

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

  • ํŒŒ์‹ฑ์— ์‹คํŒจํ•˜์˜€์„ ๋•Œ ์–ด๋–ป๊ฒŒ ์—๋Ÿฌ์ฒ˜๋ฆฌ๋ฅผ ํ• ์ง€ ๊ณ ๋ฏผํ•˜์˜€๋‹ค.
    • ๊ฐœ๋ฐœ์ž์—๊ฒŒ๋งŒ ๋ณด์—ฌ์ค˜์•ผ ํ• ์ง€, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ค˜์•ผ ํ• ์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•˜๊ณ  ์•ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์—๋Ÿฌ๋ฅผ ๋ณด๋Š” ๊ฒƒ์ด ์ ์ ˆํ•˜๋‹ค๋Š” ํŒ๋‹จ์— ์–ผ๋Ÿฟ์„ ๋„์šฐ๋„๋ก ๊ตฌ์„ฑํ•˜์˜€๋‹ค.
  • Navigation Bar๋ฅผ MainViewController์—์„œ๋งŒ ์ˆจ๊ธธ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • View Life Cycle์„ ํ™œ์šฉํ•˜์—ฌ ๋ทฐ๊ฐ€ ๋ณด์—ฌ์งˆ๋•Œ ์ˆจ๊ธฐ๊ณ , ์‚ฌ๋ผ์งˆ๋•Œ ๋‹ค์‹œ ๋‚˜ํƒ€๋‚ด๋„๋ก ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค.
  • MainViewController์—์„œ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฅธ Label์˜ Text๋ถ€๋ถ„์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • ์Šคํ† ๋ฆฌ ๋ณด๋“œ์—์„œ Label์„ ์ง์ ‘ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์—ˆ์ง€๋งŒ, ์Šคํ† ๋ฆฌ๋ณด๋“œ ์˜์กด์„ฑ์„ ์ตœ๋Œ€ํ•œ ๋‚ฎ์ถฐ๋ณด๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ Label์— ํ…์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ดํ›„ ํŠน์ • ๊ธ€์ž๋งŒ ์‚ฌ์ด์ฆˆ๊ฐ€ ์ปค์งˆ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ–ˆ๋‹ค.
  • ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•˜๋Š” String์„ ๋ณ€์ˆ˜๋กœ ๋”ฐ๋กœ ๋‹ด์•„ enumํƒ€์ž…์œผ๋กœ ๋ฌถ์–ด๋‘์–ด ๋ฆฌํŒฉํ† ๋ง์„ ์ง„ํ–‰ํ–ˆ๋‹ค.
  • ์…€์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด xib๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ปค์Šคํ…€ ์…€์„ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค.
  • ์…€์„ ํ„ฐ์น˜ํ•˜๋Š” ์‹œ์ ์— ํ•ด๋‹น ์…€์˜ ์ •๋ณด๊ฐ€ ๋‹ค์Œ ํ™”๋ฉด์œผ๋กœ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.
  • ์„ ํƒ๋œ ์…€์ด ์„ ํƒ๋œ ํ”์ ์ด ๋‚จ์•„์žˆ์–ด ์ด๋ฅผ ์—†์• ๊ธฐ ์œ„ํ•ด ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
    • delegate๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์…€์ด ๋ˆŒ๋ ธ์„ ๋•Œ ์‹œ์ ์— deselectํ•˜๋„๋ก ๊ตฌ์„ฑํ•ด๋ณด์•˜๋‹ค.
  • ResultType์ด ๊ฐ€๋…์„ฑ์ด ์ข‹๊ณ , ์—๋Ÿฌ์— ์œ ์—ฐํžˆ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋„๋ก decode ๋ฉ”์†Œ๋“œ๋ฅผ ResultType์œผ๋กœ ๊ตฌํ˜„ํ•ด๋ณด์•˜๋‹ค.
    • fail์‹œ ์ €ํฌ๊ฐ€ ๋งŒ๋“  ์—๋Ÿฌ์˜ description์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ ค์ฃผ๊ณ  success์‹œ view๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํƒ€๊ฒŒ๋” ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

2-2 ์˜๋ฌธ์ 

  • ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•ด๋ณด๋ ค ๋…ธ๋ ฅํ•˜์˜€๋Š”๋ฐ, ์ ์ ˆํ•˜๊ฒŒ ํ•œ ๊ฒƒ์ด ๋งž์„๊นŒ?
  • ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์„ ํ•  ๋•Œ, ์ฆ‰ ์ƒํƒœ๊ด€๋ฆฌ๋ฅผ ํ•  ๋•Œ ๋‹จ์ˆœํžˆ ํ”„๋กœํผํ‹ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ• ๋ง๊ณ  ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์—†๋Š”๊ฑธ๊นŒ?
  • TableView์˜ DataSorce๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์…€์„ ์„ค์ •ํ•  ๋•Œ ์˜ˆ์ „๋ฒ„์ „์œผ๋กœ ์„ค์ •์„ ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š”์ง€ ์ตœ์‹ ๋ฒ„์ „(iOS 14) ๋ฐฉ์‹์œผ๋กœ ์„ค์ •์„ ํ•ด์ฃผ์–ด์•ผํ•˜๋Š”์ง€ ์–ด๋–ค๊ฒŒ ์ ์ ˆํ•œ์ง€๊ฐ€ ์˜๋ฌธ์ด๋‹ค.
  • MainViewController ๋‚ด๋ถ€์— setUpView() ๋ฉ”์†Œ๋“œ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์€ ์ผ์„ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹Œ์ง€?

2-3 Trouble Shooting

1. ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ํŠน์ • ViewController์—์„œ๋งŒ ์ˆจ๊น€ ์ฒ˜๋ฆฌํ•˜๊ธฐ

  • ์ƒํ™ฉ MainViewController๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๋ทฐ๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ฆ‰ MainViewController๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ฐ”๋ฅผ ์ˆจ๊น€์ฒ˜๋ฆฌ ํ•ด์•ผ ํ•œ๋‹ค.

  • ์‹œ๋„ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ๊ฐ์ถ”๊ธฐ

    • ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํด๋ฆญ ํ›„
    • ์šฐ์ธก Inspector์—์„œ Shows Navigation Bar ์ฒดํฌ๋ฅผ ํ•ด์ œํ•ด์ค€๋‹ค.
    • https://camo.githubusercontent.com/8ee13833a1e08e99b2f1c058d511eb599201481275636a037336211633154760/68747470733a2f2f692e696d6775722e636f6d2f386a70416d31772e706e67
  • ์ฝ”๋“œ๋กœ ๊ฐ์ถ”๊ธฐ

    • ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ๋กœ Embed In ๋˜์–ด์žˆ๋Š” ViewController ๋‚ด๋ถ€์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.
      • self.navigationController?.isNavigationBarHidden = true
  • ์ด์œ  ์œ„์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์€ Navigation Controller์— ์—ฐ๊ฒฐ๋˜์–ด์žˆ๋Š” ๋ชจ๋“  ViewController์˜ Navigation Bar๊ฐ€ ์ˆจ๊ฒจ์ง„๋‹ค.

  • ํŠน์ • ViewController์˜ Navigation Bar๋ฅผ ์ˆจ๊ธฐ๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

  • ํ•ด๊ฒฐ ํ•ด๋‹น ๋ฐฉ๋ฒ•์€ View Life Cycle ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ทฐ๊ฐ€ ํ™”๋ฉด์— ๋ณด์ผ ๋•Œ Navigation Bar๋ฅผ ์ˆจ๊ธฐ๊ณ  ๋‹ค๋ฅธ์ฐฝ์œผ๋กœ ๋„˜์–ด๊ฐˆ๋•Œ ๋‹ค์‹œ ๋ณด์ด๊ฒŒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
}

2. ์…€์ด Select ๋˜์—ˆ์„ ๋•Œ ์‚ฌ๋ผ์ง€์ง€ ์•Š๋Š” ํšŒ์ƒ‰๋ฐฐ๊ฒฝ

[์…€์ด Select๋˜์—ˆ์„ ๋•Œ ๋‚จ๋Š” ํšŒ์ƒ‰๋ฐฐ๊ฒฝ ์—†์• ๊ธฐ]

  • https://camo.githubusercontent.com/6b0a15f162920b994ec4e1fb9859fb7f06e7348fdef04018f6e48f8009a1a4a0/68747470733a2f2f692e696d6775722e636f6d2f386154724743622e676966

  • ์ƒํ™ฉ ์…€์„ ํด๋ฆญํ•ด์„œ ํ™”๋ฉด์ „ํ™˜ํ›„ ๋‹ค์‹œ ๋Œ์•„์™€๋„ ์…€์˜ ๋ฐฐ๊ฒฝ์ƒ‰์ด ์•ˆ์—†์–ด์ง€๋Š” ํ˜„์ƒ์ด ์ผ์–ด๋‚ฌ๋‹ค.

  • ์ด์œ  ํ…Œ์ด๋ธ”๋ทฐ์˜ ์…€์ด ์„ ํƒ๋˜๋ฉด ํšŒ์ƒ‰์œผ๋กœ ๋ณ€ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ๋ฌธ์ œ๋Š” ์ด๋ ‡๊ฒŒ ๋ณ€ํ•œ ์ƒ‰์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋œ๋‹ค.

  • ํ•ด๊ฒฐ ํ…Œ์ด๋ธ” ๋ทฐ์˜ ์…€์„ ์„ ํƒํ•˜๋ฉด ํšŒ์ƒ‰์œผ๋กœ ๋ณ€ํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์›๋ž˜ ์ƒ‰์œผ๋กœ ๋ฐ”๋กœ ๋Œ์•„์˜ค๊ฒŒ ํ•˜๋ ค๋ฉด ์•„๋ž˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

    extension ItemListViewController: UITableViewDelegate {
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            tableView.deselectRow(at: indexPath, animated: true)
        }
    }
  • ์ ์šฉํ›„

  • https://camo.githubusercontent.com/a7c7277a10d19e11e5babce23aaffacc17f8a6b4f6311ea859ad75da5c2689a2/68747470733a2f2f692e696d6775722e636f6d2f424e6b6f4c31682e676966


3. ์„ ํƒํ•œ ์…€์˜ indexPath๋ฅผ DataSource๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์•Œ๋ ค๋ฉด?

tableView์˜ ์†์„ฑ์ค‘ indexPathForSelectedRow ๊ฐ€ ์žˆ๋Š”๋ฐ, ์„ ํƒ๋œ row(Cell)์˜ indexPath๋ฅผ ๊ฐ€์ ธ์™€ ํ™œ์šฉํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

var indexPathForSelectedRow: IndexPath? { get }

4. ํ™”๋ฉด ์ „ํ™˜ ์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•

  • performSegue์‹œ sender๋ฅผ nil์ด ์•„๋‹ˆ๋ผ ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅํ›„
  • prepare์‹œ sender๋ฅผ ๋‹ค์šด์บ์ŠคํŒ…์„ ํ™œ์šฉํ•˜์—ฌ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.
extension ItemListViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "ItemDetailView", sender: items[indexPath.row])
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let item = sender as? ExpositionItem,
          let nextViewController = segue.destination as? ItemDetailViewController else {
          return
      }
    nextViewController.item = item
}
  • prepare ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์—์„œ ์„ ํƒ๋œ ์…€์˜ indexPath๋ฅผ ๊ตฌํ•ด์„œ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์กด์žฌํ•œ๋‹ค.
extension ItemListViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "ItemDetailView", sender: nil)
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let indexPath = itemListTableVIew.indexPathForSelectedRow,
          let nextViewController = segue.destination as? ItemDetailViewController else {
        return
    }
    nextViewController.item = items[indexPath.row]
}

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

  • ํ…Œ์ด๋ธ”๋ทฐ์˜ ์ „๋ฐ˜์ ์ธ ๋™์ž‘ ๋ฐฉ์‹
  • ์ฃผ์–ด์ง„ JSON ๋ฐ์ดํ„ฐ๋ฅผ ํŒŒ์‹ฑํ•˜์—ฌ ํ…Œ์ด๋ธ”๋ทฐ์— ํ‘œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ํ™”๋ฉด ์ „ํ™˜์‹œ ์„ ํƒ๋œ ์—ด์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ๋ฐฉ๋ฒ•
  • ํ…Œ์ด๋ธ”๋ทฐ์˜ ์…€์˜ ์žฌ์‚ฌ์šฉ ์ดํ•ด
  • ์…€์˜ ํ–‰ ์„ ํƒ์— ๊ด€๋ จ๋œ ์†์„ฑ์˜ ์ดํ•ด
  • NSMutableAttributedString addAttribute ๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํฐํŠธ ์Šคํƒ€์ผ์„ ํŽธ์ง‘ํ•˜๋Š” ๋ฐฉ๋ฒ•
  • UIImage์— image๋ฅผ ์ฝ”๋“œ๋กœ ์„ค์ •ํ•˜๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•
  • Navigation Bar item์— ๋Œ€ํ•œ ์ดํ•ด
  • xib๋ฅผ ํ™œ์šฉํ•ด์„œ UI๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•

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

  • ์Šคํ† ๋ฆฌ๋ณด๋“œ ๋ถ„ํ• 
  • ํ…Œ์ŠคํŠธ์ฝ”๋“œ ์—๋Ÿฌ ์ˆ˜์ •
  • ํ™”๋ฉด๊ฐ„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ์‹œ ๋ฉ”์†Œ๋“œ ํ™œ์šฉ
  • ์˜คํƒ€ ์ˆ˜์ •
  • ๋ฐฐ์—ด์˜ ์ธ๋ฑ์Šค๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์กฐํšŒํ•˜๋„๋ก ๊ฐœ์„ 

top

STEP 3 : ์˜คํ† ๋ ˆ์ด์•„์›ƒ ์ ์šฉ

๋ชจ๋“  ์•„์ดํฐ ๊ธฐ๊ธฐ์— ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ƒํ™ฉ์—์„œ๋„ ์ •์ƒ์ ์œผ๋กœ ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

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

  • Dynamic Type ์™ธ์—๋„ Voice Over๋„ ๊ณ ๋ คํ•ด๋ณด์•˜๋‹ค.
    • Cell์˜ ๊ฒฝ์šฐ ์ด๋ฏธ์ง€์— accessibilityLabel๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ์ฝ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋ฏธ์ง€์˜ ์ด๋ฆ„๋„ ์ฝ์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.
  • ์ด์ „์— static ๋ฉ”์„œ๋“œ๋กœ ํ™œ์šฉํ•˜์˜€๋˜ JSONParser ํƒ€์ž… enum์„ struct๋กœ ๋ฐ”๊พธ์–ด์ฃผ์—ˆ๋‹ค.
    • static์˜ ๊ฒฝ์šฐ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋ฉ”๋ชจ๋ฆฌ์— ๊ณ„์† ๋‚จ์•„์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ ๋ฆฌํŒฉํ† ๋ง ํ•ด์ฃผ์—ˆ๋‹ค.
  • ์ตœ์†Œํ•œ์˜ ์ œ์•ฝ์กฐ๊ฑด์œผ๋กœ Auto Layout์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณ ๋ฏผํ•ด๋ณด์•˜๋‹ค.
  • ์ฒซ๋ฒˆ์งธ ๋ทฐ์˜ Orientation์„ ์„ธ๋กœ๋กœ ๊ณ ์ •ํ•ด์ฃผ๋ คํ–ˆ๋Š”๋ฐ, ํ•ด๋‹น ๋ทฐ๋งŒ ์„ธ๋กœ๋กœ ๊ณ ์ •์„ ์‹œํ‚ค๊ฒŒ ๋˜๋ฉด ๊ณ ์ •์ด ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.
    • ์ด๋Š” ์ฒซ๋ฒˆ์งธ๋ทฐ์˜ SuperView์ธ navigation view์˜ orientation์ด ์„ค์ •๋˜์–ด ์žˆ์ง€์•Š์•„ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ์˜€๋‹ค. ๊ทธ๋ž˜์„œ navigation์˜ ๋Œ€๋ฆฌ์ž๋ฅผ ์ฒซ๋ฒˆ์งธ๋ทฐ๋กœ ์„ค์ •ํ•˜๊ณ  navigation ์˜ orientation์„ ์„ค์ •ํ•ด์ฃผ์–ด ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

3-2 ์˜๋ฌธ์ 

  • attributedText๋ฅผ ํ™œ์šฉํ•  ๋•Œ ์ ์šฉํ•œ ๊ธ€์ž๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๊ธ€์ž๋Š” Dynamic Type ์ ์šฉ์ด ์™œ ์•ˆ๋ ๊นŒ?
  • Navigation Controller๋ฅผ ํ™œ์šฉํ•˜์—ฌ ViewController์˜ Oreientations์„ ์„ค์ •ํ•ด์ค„ ๋•Œ Navigation Controller์—์„œ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š”์ง€, ์•„๋‹ˆ๋ฉด UINavigationControllerDelegate์„ ์ฑ„ํƒํ•˜์—ฌ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ• ์ง€?
  • button์˜ style ์ค‘์— default์™€ plain์˜ ์ •ํ™•ํ•œ ์ฐจ์ด์ ์„ ์•Œ๊ณ ์‹ถ๋‹ค.

3-3 Truoble Shooting

1. attributedText๋ฅผ ์ ์šฉํ•ด์ค€ Label์˜ Dynamic Type ์ ์šฉํ•˜๊ธฐ

  • ์ƒํ™ฉ ๋ถ€๋ถ„์ ์œผ๋กœ ํ…์ŠคํŠธ ์Šคํƒ€์ผ์„ ํŽธ์ง‘ํ•ด์ค€ Label์ด ํŽธ์ง‘ํ•ด์ค€ ๋ถ€๋ถ„์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๊ธ€์ž๋“ค์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ Dynamic Type์ด ์ ์šฉ์ด ์•ˆ๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ๋‹ค.
  • ์ด์œ  ์•Œ๊ณ ๋ณด๋‹ˆ ํŽธ์ง‘ํ•ด์ค€ ๋ถ€๋ถ„(prefix)์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๊ธ€์ž์˜ ํฐํŠธ๋„ ๊ฐ™์ด ์ ์šฉํ•ด์ค˜์•ผ ๋ฌ๋‹ค.
    • ๋งจ ์ฒ˜์Œ ๊ธ€์ž์˜ TextStyle์ด title3๋กœ ์„ค์ •๋˜์–ด์žˆ๋Š”๋ฐ addAttribute๋ฅผ ํ•˜๋Š” ์ˆœ๊ฐ„ TextStyle์ด ํ’€๋ฆฌ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.
  • ํ•ด๊ฒฐ ๋”ฐ๋ผ์„œ ๋‚˜๋จธ์ง€ ํ…์ŠคํŠธ์— ๋Œ€ํ•ด์„œ๋„ TextStyle์„ ์ง€์ •ํ•ด์ค€ ํ›„ addAttribute ํ•ด์ฃผ๋‹ˆ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.

2. ๋ฉ”์ธ์˜ ํ•˜๋‹จ ๋ฒ„ํŠผ์ด ์œ„ Label๊ณผ ๊ฒน์ณ๋ณด์ด๋Š” ํ˜„์ƒ

  • ์ƒํ™ฉ Dynamic Type์„ ์ตœ๋Œ€ํ•œ ๋Š˜๋ ธ์„ ๋•Œ ํ•˜๋‹จ์˜ ๋ฒ„ํŠผ titleLabel์ด ์ปค์กŒ์ง€๋งŒ ์ด์— ๋”ฐ๋ผ StackView์˜ ๋†’์ด๊ฐ€ ๋Š˜์–ด๋‚˜์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ๋‚˜ํƒ€๋‚ฌ๋‹ค.
  • ์‹œ๋„1 ๋ ˆ์ด์•„์›ƒ์ด ์•ˆ์žกํ˜€ ์žˆ์–ด์„œ ๊ทธ๋Ÿฐ๊ฑด๊ฐ€ ์‹ถ์–ด์„œ ๋ฒ„ํŠผ์˜ ๋†’์ด๋ฅผ ์Šคํƒ๋ทฐ์™€ ๊ฐ™๊ฒŒ ์„ค์ •์„ ์ฃผ์—ˆ์œผ๋‚˜ ํ˜„์ƒ์€ ๋™์ผํ–ˆ๋‹ค.
  • ์‹œ๋„2 ๋˜ํ•œ StackView์˜ Alignment๋ฅผ center๋กœ ์ฃผ์—ˆ์„ ๋•Œ์—๋„ ์•ฝ๊ฐ„ ๊ฒน์ณ์ง์ด ์ค„๊ธด ํ–ˆ์ง€๋งŒ ๋™์ผํ•œ ๋ฌธ์ œ๋กœ ํ•ด๊ฒฐ์€ ๋˜์ง€ ์•Š์•˜๋‹ค.
  • ํ•ด๊ฒฐ ๋ฒ„ํŠผ์˜ Style์ด ์ด์ „์—” ๋ฒ„์ „ ํ˜ธํ™˜ ๋ฌธ์ œ๋กœ default๋กœ ๋งž์ถฐ์ ธ ์žˆ์—ˆ๋Š”๋ฐ, iOS 15๋ถ€ํ„ฐ ์ ์šฉ ๊ฐ€๋Šฅํ•œ Plain์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์ž ๋ ˆ์ด์•„์›ƒ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์–ด๋–ค ์ฐจ์ด๋กœ ํ•ด๋‹น ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋Š”์ง€ ์ •ํ™•ํ•œ ํŒŒ์•…์€ ์–ด๋ ค์› ๋‹ค. ๊ธฐ์กด์— Dynamic Type์ด ์ ์šฉ๋˜์ง€ ์•Š์•˜๋˜ ๋ฒ„ํŠผ์ด ์ด๋ฒˆ์— ์—…๋ฐ์ดํŠธ๊ฐ€ ๋˜๋ฉด์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ์šฉ๋˜๊ฒŒ๋” ๋ฐ”๋€Œ์—ˆ๋Š”๋ฐ ๊ทธ ๋ถ€๋ถ„ ๋•Œ๋ฌธ์ด ์•„๋‹Œ๊ฐ€ ์‹ถ๋‹ค.

3. ํŠน์ • ํ™”๋ฉด๋งŒ Orientation ๊ณ ์ •

  • ์ƒํ™ฉ ์ฒซ๋ฒˆ์งธ ๋ทฐ์ธ MainView๋งŒ Orientation์„ ๊ณ ์ • ํ•ด์ฃผ๊ณ ์‹ถ์—ˆ๋Š”๋ฐ, ์ฝ”๋“œ๋กœ ์ ์šฉ์„ ํ•ด์ฃผ๋ คํ•ด๋„ ๋ณ€ํ™”๊ฐ€ ์—†๋Š” ํ˜„์ƒ์ด ๋‚˜ํƒ€๋‚ฌ๋‹ค.
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
            return .portrait
        }
  • ์ด์œ  ์œ„ ํ”„๋กœํผํ‹ฐ๋ฅผ overrideํ•˜์—ฌ ํ™”๋ฉด ๊ณ ์ •์„ ํ•ด์ฃผ๊ณ ์‹ถ์—ˆ์ง€๋งŒ ์ ์šฉ์ด ๋˜์ง€์•Š์•˜๊ณ , ์ด์œ ๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์˜ ๋ทฐ๋“ค์˜ Hierarchy ์ƒ๋‹จ์—” NavigationController๊ฐ€ ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋‹จ ๋ทฐ์˜ Orientation์ด ๊ณ ์ •๋˜์–ด์žˆ์ง€ ์•Š์•„ ํ•˜์œ„ ๋ทฐ๋“ค์˜ Orientation ๋˜ํ•œ ์ ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.
  • ํ•ด๊ฒฐ Navigation์˜ ํด๋ž˜์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์—ฌ Orientation์„ ์ ์šฉ์‹œ์ผœ์ค„๊นŒ ํ–ˆ์ง€๋งŒ, Main๋ทฐ๋งŒ ๊ณ ์ •์‹œ์ผœ์ฃผ๊ณ  ์‹ถ์—ˆ๊ธฐ๋•Œ๋ฌธ์— ๊ตณ์ด ์ƒ์„ฑ์น˜์•Š๊ณ , UINavigationControllerDelegate๋ฅผ MainViewController์— ์ฑ„ํƒํ•˜์—ฌ ๋‚ด๋ถ€ ๋ฉ”์†Œ๋“œ์ธ navigationControllerSupportedInterfaceOrientations ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ Orientation์„ ์ฒซ ํ™”๋ฉด์—์„œ๋งŒ ๊ณ ์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•ด์ฃผ์—ˆ๋‹ค.
    extension MainViewController: UINavigationControllerDelegate {
        func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask {
            return navigationController.topViewController?.supportedInterfaceOrientations ?? .all
        }
    }

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

  • Button์˜ Configuration
  • Navigation Controller๋ฅผ ํ™œ์šฉํ•˜์—ฌ Orientation ์„ค์ •ํ•˜๊ธฐ
  • Accessibility
    • Dynamic Type
    • Voice over
  • static ๋ฉ”์†Œ๋“œ, static ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ์ •ํ™•ํ•œ ๊ฐœ๋…
    • ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

top

About

๐Ÿ‡ซ๐Ÿ‡ท ํ…Œ์ด๋ธ”๋ทฐ๋ฅผ ํ™œ์šฉํ•œ ๋‹ค์–‘ํ•œ ๊ตญ๊ฐ€์˜ ๋ฌธํ™”์œ ์‚ฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•œ ์•ฑ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Swift 100.0%