Skip to content

๐Ÿป iOS ์ปค๋ฆฌ์–ด ์Šคํƒ€ํ„ฐ ์บ ํ”„ ๐ŸŒƒ ๋งŒ๊ตญ ๋ฐ•๋žŒํšŒ

Notifications You must be signed in to change notification settings

cherrishRed/ios-exposition-universelle

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

84 Commits
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐ŸŒƒ ๋งŒ๊ตญ ๋ฐ•๋žŒํšŒ

ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„ 2022.04.11 ~ 2022.4.22 ํŒ€์› : ๐Ÿข@Doogie ๐Ÿ”ด@cherrishRed / ๋ฆฌ๋ทฐ์–ด : @TTOzzi

ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

๋งŒ๊ตญ๋ฐ•๋žŒํšŒ์˜ ์„ค๋ช…์„ ํ™•์ธํ•˜์„ธ์š”! ์–ด๋–ค ํ•œ๊ตญ์˜ ์ž‘ํ’ˆ๋“ค์ด ์žˆ๋Š”์ง€ ์ž์„ธํžˆ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”! ํฐ ๊ธ€์”จ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค!

๊ฐœ๋ฐœํ™˜๊ฒฝ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

swift xcode

ํ‚ค์›Œ๋“œ

JSON,MetaType,TableView,DynamicType,NSMutableAttributedString,์˜์กด์„ฑ ์ฃผ์ž…

STEP1

STEP1-PR

๊ธฐ๋Šฅ๊ตฌํ˜„

  • Item, Exposition ๊ตฌ์กฐ์ฒด ๊ตฌํ˜„
  • Decodable ํ™•์žฅ์„ ํ†ตํ•œ decode ๋ฉ”์„œ๋“œ ๊ตฌํ˜„

๐Ÿš€ trouble shooting

1. private(set)

์ฝ๊ธฐ ์ „์šฉ์œผ๋กœ ์ ‘๊ทผ์ œ์–ด๋ฅผ ์„ค์ •ํ•ด์ฃผ๊ณ ์ž private(set)์œผ๋กœ ์„ค์ •ํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ๋‹ค.

โœ… let ์ž์ฒด๊ฐ€ ์ฝ๊ธฐ ์ „์šฉ์ด๋ผ ์™ธ๋ถ€์—์„œ ๋ณด์•˜์„ ๋•Œ๋Š” private(set) ๊ณผ ๋™์ผํ•ด, ์ ‘๊ทผ์ œ์–ด๋ฅผ ๊ฑธ์–ด์ค„ ํ•„์š”๊ฐ€ ์—†๋Š” ๋ฌธ์ œ ์˜€๋‹ค.

2. decoder ์œ„์น˜

model VS viewcontroller ์ผ๋ฐ˜์ ์ธ ๋””์ฝ”๋”ฉ ์˜ˆ์ œ ์ฝ”๋“œ์—์„œ๋Š” decode ๋ฅผ View Controller ์—์„œ ๋งŽ์ด ์ฒ˜๋ฆฌ ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ–ˆ์œผ๋‚˜ decoder ์—์„œ๋Š” UI ๋ฅผ ๊ฑด๋“œ๋ฆฌ๋Š” ๋ถ€๋ถ„์ด ์—†์–ด ์–ด๋””์— ์œ„์น˜ํ•ด์•ผ ํ•˜๋Š”์ง€ ์˜๋ฌธ์ด์—ˆ๋‹ค.

โœ… ์ €ํฌ์˜ ํŒ๋‹จ์œผ๋กœ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ถŒ์žฅํ•˜๋Š” ๋ถ€๋ถ„์ด View Controller ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•ด Decodable ์„ ํ™•์žฅํ•ด ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด ์ฃผ๊ฒŒ ๋˜์—ˆ๋‹ค.

3. Decodable์˜ ๋ฐฐ์—ด์ด Decodable ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์ด์œ 

[Self]? == Decodable? ๋กœ ์ธ์‹์ด ๋ผ์„œ ์ •์ƒ์ ์œผ๋กœ ๋ฐ˜ํ™˜์ด ๋˜๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ ์™œ ๋ฐฐ์—ดํƒ€์ž…๊ณผ Decodableํƒ€์ž…์ด ๋™์ผ ํƒ€์ž…์œผ๋กœ ์ทจ๊ธ‰๋˜๋Š” ๊ฒƒ์ธ์ง€ ์˜๋ฌธ์ด์—ˆ๋‹ค. โœ… ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐพ์•„๋ณด๋‹ˆ ๋ฐฐ์—ด์˜ ๋‚ด๋ถ€์š”์†Œ๊ฐ€ ๋ชจ๋‘ Decodable ํƒ€์ž…์„ ์ฑ„ํƒํ•˜๋ฉด ๊ทธ ๋ฐฐ์—ด๋„ Decodable ์„ ์ฑ„ํƒํ•œ๋‹ค๊ณ  ํ•œ๋‹ค๋Š” ์ ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

4. ๋””์ฝ”๋”ฉ์—๋Ÿฌ ํ…Œ์ŠคํŠธ

JSONDecode.decode ๋ฅผ ํ• ๊ฒฝ์šฐ DecodingError ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. ์ ์ ˆํ•œ case ์— ๋งž์ถฐ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‚˜ ์—๋Ÿฌ์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์˜๋ฌธ์ด์—ˆ๋‹ค.

โœ… Error ์— ์ ‘๊ทผํ•œ ๋ฐฉ๋ฒ•

func test_Exposition_decodeํ˜ธ์ถœ์‹œ_์ž˜๋ชป๋œํŒŒ์ผ๋ช…์„๋Œ€์ž…ํ• ์‹œ_assetLoadError๊ฐ€๋ฐœ์ƒํ•˜๋Š”์ง€() throws {
    XCTAssertThrowsError(try Exposition.decode(with: "์ด์ƒํ•œ์ด๋ฆ„")) { error in
        XCTAssertEqual(error as? DataLoadError, DataLoadError.assetLoadError)
        }
    }

์ €ํฌ๊ฐ€ ์ƒ์„ฑํ•œ ์—๋Ÿฌ ํƒ€์ž…์ธ DataLoadError ์— ์ ‘๊ทผ ํ–ˆ์„ ๋•Œ์—๋Š” XCTAssertThrowsError ๋ฉ”์„œ๋“œ๋กœ ์—๋Ÿฌ๋ฅผ ๋ฐ›๊ณ  XCTAssertEqual ๋กœ ๋น„๊ตํ•ด ํ…Œ์ŠคํŠธ๋ฅผ ์„ฑ๊ณตํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ DecodingError๋Š” Equatable์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ์ง€ ์•Š์•„ ๋น„๊ต๊ฐ€ ๋ถˆ๊ฐ€๋Šฅ ํ–ˆ๋‹ค.

func test_ํ”„๋กœํผํ‹ฐ์˜ํƒ€์ž…์ด์ž˜๋ชป๋œ๊ฐ์ฒด์—์„œ_decodeํ˜ธ์ถœ์‹œ_typeMismatch์—๋Ÿฌ๊ฐ€๋ฐœ์ƒํ•˜๋Š”์ง€() throws {
    do {
        try DummyForWrongType.decode(with: "exposition_universelle_1900")
        XCTFail()
    } catch DecodingError.typeMismatch(let key, let value) {
        print(print("\n key: \(key) \n value: \(value) \n"))
    } catch {
        XCTFail()
        }
    }

๊ทธ๋ž˜์„œ do try ๋ฌธ์„ ์‚ฌ์šฉํ•ด์„œ ์›ํ•˜๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋œ ๊ฒฝ์šฐ ํ•ด๋‹น ๋‚ด์šฉ์„ ํ”„๋ฆฐํŠธ ํ•ด ํ†ต๊ณผํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ๊ณ  ์›ํ•˜๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” ์‹คํŒจํ•˜๋„๋ก ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

๋ฐฐ์šด ๊ฐœ๋…

  • JSON
  • Meta Type
  • Asset

STEP2

STEP2-PR

๊ธฐ๋Šฅ๊ตฌํ˜„

  • View ๊ตฌ์„ฑ, ViewController ๊ตฌ์„ฑ
  • Table ๋ทฐ ๊ตฌ์„ฑ
  • JSON ๋ฐ์ดํ„ฐ๋ฅผ ๋ทฐ์— ๋„์œ„๊ธฐ

๐Ÿš€ trouble shooting

1. auto layout Y ํฌ์ง€์…˜ or height ์„ค์ •

์Šคํฌ๋กค ๋ทฐ์˜ ๋†’์ด๋ฅผ ๋”ฐ๋กœ ์„ค์ •ํ•ด ์ฃผ์ง€ ์•Š์œผ๋ฉด Y positin or height๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒ ํ–ˆ๋‹ค

โœ… ์ด ์˜ค๋ฅ˜์˜ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์œผ๋กœ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ํ™•์ธํ–ˆ๋‹ค.

  1. ๋†’์ด ์„ค์ • ํ›„ priority ๋‚ฎ์ถ”๊ธฐ

  2. Intrinsic Size ์˜ต์…˜ Placeholder๋กœ ๋ฐ”๊ฟ”์ฃผ๊ธฐ

๋‘ ๋ฐฉ๋ฒ• ์ค‘ Y ์ถ•๋งŒ ์ง€์ •ํ•ด๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒซ๋ฒˆ ์งธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ ํ–ˆ๋‹ค.

2. alert์˜ ์žฌ์‚ฌ์šฉ์„ฑ

    func showAlert() {
        let alert = UIAlertController(title: "์˜ค๋ฅ˜", message: "๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", preferredStyle: .alert)
        let action = UIAlertAction(title: "ํ™•์ธ", style: .default, handler: nil)
        alert.addAction(action)
        self.present(alert, animated: true, completion: nil)
    }

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ ์œ„์™€ ๊ฐ™์ด ์–ผ๋Ÿฟ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ๋‘ ๊ฐœ์˜ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ์— ๊ฐ๊ฐ ํ•˜๋‚˜์”ฉ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š”๋ฐ ์ง€๊ธˆ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ํ•œ๋ฒˆ์”ฉ ๋ฐ–์— ์‚ฌ์šฉ์„ ํ•˜์ง€ ์•Š์•„์„œ ๊ฐ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ์— ์ƒ์„ฑ์„ ํ–ˆ์ง€๋งŒ ์ด๋Ÿฐ ์žฌ์‚ฌ์šฉ์„ฑ์ด ์žˆ๋Š”๋ฐ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜์˜ ํŒŒ์ผ๋กœ ๋งŒ๋“ค์–ด์„œ ๊ด€๋ฆฌ๋ฅผ ํ•ด์ค˜๋„ ๊ดœ์ฐฎ์€์ง€ ๊ณ ๋ฏผ์ด์—ˆ๋‹ค.

โœ… ๊ฒฐ๊ตญ UIViewController ์˜ extension ์— showAlert() ๋ฉ”์„œ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์—ฌ์ฃผ๋Š” ๋ฐฉ๋ฒ•์„ ์ฑ„ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

๋ฐฐ์šด ๊ฐœ๋…

  • defaultContentConfiguration
  • TableView
  • TableViewDataSource
  • TableVeiwDelegate
  • ScrollView

STEP3

STEP3-PR

๊ธฐ๋Šฅ๊ตฌํ˜„

  • Dynamic Type ์ ์šฉ
  • Dynamic Type์— ๋”ฐ๋ฅธ ์Šคํƒ๋ทฐ axis์ „ํ™˜
  • ์ „์ฒด์ ์ธ AutoLayout ์ˆ˜์ •
  • ์ฒซ๋ฒˆ์จฐ ํ™”๋ฉด ์„ธ๋กœ๋ชจ๋“œ๋กœ ๊ณ ์ •, ๊ฐ€๋กœ๋ชจ๋“œ ์„ธ๋ถ€ ์„ค์ •

๐Ÿš€ trouble shooting

1. ViewController์˜ init (์˜์กด์„ฑ ์ฃผ์ž…)

[๊ธฐ์กด ์ฝ”๋“œ]

final class ItemViewController: UIViewController {
    @IBOutlet weak private var itemImageView: UIImageView!
    @IBOutlet weak private var descriptionLabel: UILabel!
    
    var item: Item?

์œ„ ์ฝ”๋“œ์—์„œ item์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ๋Š” ItemViewController์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด ์ง์ ‘ ์ ‘๊ทผ์„ ํ•ด์คฌ์–ด์•ผ ํ–ˆ๋Š”๋ฐ ๊ทธ๋Ÿฌ๋ฉด ์™ธ๋ถ€์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋„๋ก ํ•˜๋Š” ์ ‘๊ทผ์ œ์–ด ์„ค์ •๋„ ํ•˜์ง€ ๋ชปํ•˜๊ณ  ๋˜ ์ง์ ‘ ์ ‘๊ทผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๋ฌธ์ œ์ ์œผ๋กœ ๋ง์”€ํ•ด ์ฃผ์…จ๊ณ  storyboard creator init์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ•ด๋ณด๊ธธ ๊ถŒ์œ ํ•ด์ฃผ์…จ๋‹ค

final class ItemViewController: UIViewController {
    @IBOutlet weak private var itemImageView: UIImageView!
    @IBOutlet weak private var descriptionLabel: UILabel!
    
    private let item: Item
    
    init(item: Item) {
        self.item = item
        super .init(nibName: nil, bundle: nil)
    }
    
    init?(_ coder: NSCoder, _ item: Item) {
        self.item = item
        super.init(coder: coder)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

โœ… ๊ทธ๋ž˜์„œ ๊ณต๋ถ€ ํ›„ ์œ„ ๊ณผ์ •์„ ํ†ตํ•ด ItemViewController์˜ init์„ ํ†ตํ•ด item์„ ํ• ๋‹นํ•ด์ฃผ๋„๋ก ํ–ˆ๋‹ค.

++ ์ถ”๊ฐ€ ๋‚ด์šฉ

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

fatalError๋Š” ์ผ๋ถ€๋Ÿฌ ํฌ๋ž˜์‰ฌ๋ฅผ ๋‚ด๋Š” ๋ฉ”์„œ๋“œ๋กœ ์‚ฌ์šฉ์‹œ ๋ฆฌ์ ์‚ฌ์œ ์— ํ•ด๋‹นํ•œ๋‹ค๊ณ  ํ•œ๋‹ค (์ƒ๊ฐํ•ด๋ณด๋‹ˆ ์ผ๋ถ€๋Ÿฌ ํฌ๋ž˜์‰ฌ๋ฅผ ๋‚ด๋Š” ํ–‰์œ„ ์ž์ฒด๊ฐ€ ๋ง์ด ์•ˆ๋˜๋Š” ๋“ฏ..)

required init?(coder: NSCoder) {
    super.init(coder: coder)
    }

๊ทธ๋ž˜์„œ ์œ„์™€ ๊ฐ™์ด super๋ฅผ ํ†ตํ•ด ๊ธฐ์กดํ•ด ํ•ด์ฃผ๋˜ ์ž‘์—…๋งŒ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ์œผ๋ฉฐ ํ˜ธ์ถœ ๋ถ€์—์„œ๋Š”

let itemVC = storyboard
    .instantiateViewController(identifier: ItemViewController.identifier,
                            creator: { coder -> ItemViewController? in
        return .init(coder, item)
    })

์œ„์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ด ๋ฐ˜ํ™˜๊ฐ’์„ ์˜ต์…”๋„๋กœ ์ˆ˜์ •ํ•ด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด nil์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ์—ˆ๋‹ค.

์ด์—๋”ฐ๋ผ

init(item: Item) {
    self.item = item
    super .init(nibName: nil, bundle: nil)
}

์ฒ˜์Œ์—๋Š” nil์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์•ˆ๋  ๊ฒƒ ๊ฐ™์•„์„œ nil์ด๋ฉด ์œ„ ์ดˆ๊ธฐํ™” ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋นˆ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ ์œ„ ์ฝ”๋“œ๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์•„ ์ œ๊ฑฐ

2. ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•œ ์˜์กด์„ฑ ๋‚ฎ์ถ”๊ธฐ

Heritage ์™€ ListViewController ์‚ฌ์ด์˜ ์˜์กด๋„๊ฐ€ ๋„ˆ๋ฌด ๋†’์€ ๊ฒƒ ๊ฐ™์•„ ์˜์กด์„ฑ์„ ๋‚ฎ์ถฐ๋ณด๊ธฐ๋กœ ํ•˜์˜€๋‹ค.

โœ… Item ์ด๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ƒ์„ฑํ•ด ์˜์กด๋„๋ฅผ ๋‚ฎ์ถฐ ๋ณด์•˜๋‹ค. Heritage -> <-ListViewController ์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ Heritage -> Item <-ListViewController ์ด๋ ‡๊ฒŒ ์ˆ˜์ •ํ–ˆ๋‹ค.

3. AutoLayout(accessability ์— ๋”ฐ๋ฅธ ์ •๊ฐˆํ•œ UI)

accessability ์˜ dynamic font ๋ฅผ ์ง€์›ํ–ˆ์Šต๋‹ˆ๋‹ค. ํฐํŠธ์˜ ํฌ๊ธฐ๊ฐ€ ๋„ˆ๋ฌด ์ปค์ง€๋ฉด UI์˜ ๊ฐ€๋…์„ฑ์ด ํ˜„์ €ํžˆ ๋–จ์–ด์ง€๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

โœ…

  • main View ์˜ ๋ฒ„ํŠผ์ด ์œ„์˜ ์ปจํ…์ธ ์™€ ๊ฒน์น˜์ง€ ์•Š๋„๋ก maximumContentSizeCategory ์‚ฌ์ด์ฆˆ๋ฅผ .accessibilityExtraLarge ๋กœ ์„ค์ •ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • 2๋ฒˆ ์งธ ์Šคํฌ๋กค ๋ทฐ์˜ accessibilityExtraLarge ์‚ฌ์ด์ฆˆ ์ด์ƒ์˜ ๋ทฐ์—์„œ๋Š” ์‚ฌ์ง„๊ณผ ๊ธ€์”จ์˜ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด์„œ stackView ๋ฅผ ์„ธ๋กœ๋กœ ๋Œ๋ฆฌ๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.

4. ํ™”๋ฉดํšŒ์ „

โœ… ์ฒซ๋ฒˆ์งธ ํ™”๋ฉด์„ ๊ณ ์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ๋ฒ•๋“ค์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. mainViewController ์—์„œ AppDelegate ๋ฅผ ๋ฐ›์•„์™€์„œ ๊ณ ์ •์„ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  2. AppDelegate ๋‚ด๋ถ€์—์„œ mainViewController ๋ฅผ ๋ฐ›์•„์™€ ๊ณ ์ •ํ•ด์ฃผ๊ธฐ
  3. AppDelegate ์™€ mainViewController ์‚ฌ์ด์˜ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ๊ทธ ๊ฐ์ฒด์—์„œ ๊ณ ์ •ํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ
  4. supportedInterfaceOrientations ๋ฉ”์„œ๋“œ๋ฅผ override ํ•ด์„œ ํ™”๋ฉด ๊ณ ์ •ํ•˜๊ธฐ

1, 2, 3 ๊ณผ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์„ ์‹œ๋„ํ•ด ๋ณด์•˜์ง€๋งŒ AppDelegate ์™€ mainViewController ์‚ฌ์ด์˜ ์˜์กด์„ฑ์ด ๋†’์•„ ์ง„๋‹ค๋Š” ์ ๋“ฑ์˜ ๋‹จ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๊ณ  ๊ฒฐ๊ตญ์—” ExpoNavigationController ์™€ mainViewController ์— ์•„๋ž˜์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด ์ฃผ์–ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค.

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    guard let _ = self.topViewController as? MainViewController else {
        return .all
    }
    return .portrait
}

๊ฐ€๋กœ์ƒํƒœ์—์„œ 2๋ฒˆ์งธ ํ™”๋ฉด์œผ๋กœ ํ™”๋ฉด ํšŒ์ „์ด ์ผ์–ด๋‚ฌ์„ ๋•Œ ํšŒ์ „์ด ๋˜๋Š” ์ƒํ™ฉ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„œ

viewDidAppear ์— attemptRotationToDeviceOrientation ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ์ฃผ์—ˆ๋‹ค.

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    UIViewController.attemptRotationToDeviceOrientation()
}

5. ๊ธ€์”จ ํฌ๊ธฐ์— ๋”ฐ๋ฅธ ์ œ์•ฝ ์กฐ๊ฑด ๋ณ€๊ฒฝ

func changeItemStackViewSetting(){
        let category = UIApplication.shared.preferredContentSizeCategory
        switch category {
        case UIContentSizeCategory.accessibilityExtraLarge, UIContentSizeCategory.accessibilityExtraExtraLarge, UIContentSizeCategory.accessibilityExtraExtraExtraLarge:
            itemStackView.axis = .vertical
            labelStackView.leadingAnchor.constraint(equalTo: itemStackView.leadingAnchor, constant: 0.0).isActive = true
            labelStackView.trailingAnchor.constraint(equalTo: itemStackView.trailingAnchor, constant: 0.0).isActive = true
            itemImageView.widthAnchor.constraint(equalTo: itemStackView.widthAnchor, multiplier: 0.6).isActive = true

        default:
            itemStackView.axis = .horizontal
        }
    }

์œ„์ฝ”๋“œ๋Š” ๊ธ€์”จ ํฌ๊ธฐ๊ฐ€ ๋ฐ”๋€œ์— ๋”ฐ๋ผ cell์˜ ์ œ์•ฝ ์กฐ๊ฑด์„ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ธฐ๋Šฅ์ธ๋ฐ ์‚ฌ์‹ค ์ด๋Š” ์ œ์•ฝ ์กฐ๊ฑด์„ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๊ธ€์”จ ํฌ๊ธฐ๊ฐ€ ๋ฐ”๋€” ๋•Œ ๋งˆ๋‹ค ์ƒˆ ์ œ์•ฝ ์กฐ๊ฑด์„ ๋งŒ๋“ค์–ด ์ฃผ๋Š” ๊ฒƒ์ด๋ผ ๊ณ„์† ํ•ด์„œ ์Œ“์ด๊ฒŒ ๋œ๋‹ค.

โœ…

private lazy var labelLeadingConstraint = labelStackView.leadingAnchor.constraint(equalTo: itemStackView.leadingAnchor, constant: 0.0)
private lazy var labeltraillingConstraint = labelStackView.trailingAnchor.constraint(equalTo: itemStackView.trailingAnchor, constant: 0.0)
private lazy var ImageViewWidthConstraint = itemImageView.widthAnchor.constraint(equalTo: itemStackView.widthAnchor, multiplier: 0.6)

func changeItemStackViewSetting(){
        let category = UIApplication.shared.preferredContentSizeCategory
        switch category {
        case UIContentSizeCategory.accessibilityExtraLarge, UIContentSizeCategory.accessibilityExtraExtraLarge, UIContentSizeCategory.accessibilityExtraExtraExtraLarge:
            itemStackView.axis = .vertical
            labelLeadingConstraint.isActive = true
            labeltraillingConstraint.isActive = true
            ImageViewWidthConstraint.isActive = true

        default:
            itemStackView.axis = .horizontal
            labelLeadingConstraint.isActive = false
            labeltraillingConstraint.isActive = false
            ImageViewWidthConstraint.isActive = false
        }
    }

๊ทธ๋ž˜์„œ ๊ฐ๊ฐ์˜ ์ œ์•ฝ ์กฐ๊ฑด์„ ๋ณ€์ˆ˜๋กœ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™” ์‹œ์ผœ์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

6. ํฐํŠธ ๋ณ€๊ฒฝ์‹œ ์•ž์ชฝ text๋กœ ๋ฒ”์œ„ ์„ค์ •์‹œ ์ ์šฉ์ด ์•ˆ๋˜๋Š” ๋ฌธ์ œ

private func changeFontSize(for expoInfo: Exposition) {
    let bodyFont = UIFont.preferredFont(forTextStyle: .body)
    visitorsLabel.changeFontSize(bodyFont, targetString: "๋ฐฉ๋ฌธ๊ฐ")
    locationLabel.changeFontSize(bodyFont, targetString: "๊ฐœ์ตœ์ง€")
    durationLabel.changeFontSize(bodyFont, targetString: "๊ฐœ์ตœ ๊ธฐ๊ฐ„")
    }

private func changeFontSize(for expoInfo: Exposition) {
    let bodyFont = UIFont.preferredFont(forTextStyle: .body)
    visitorsLabel.changeFontSize(bodyFont, targetString: ": \(ExpoNumberFormatter.changeVisitorsFormat(from: expoInfo.visitors) ?? "์ •๋ณด ์—†์Œ")")
    locationLabel.changeFontSize(bodyFont, targetString: ": \(expoInfo.location)")
    durationLabel.changeFontSize(bodyFont, targetString: ": \(expoInfo.duration)")
    }

์ตœ์ดˆ์— "๋ฐฉ๋ฌธ๊ฐ", "๊ฐœ์ตœ์ง€" ๋“ฑ ์ด๋Ÿฐ ์ œ๋ชฉ? ๊ฐ™์€ ๊ณณ์— ๋‹ค๋ฅธ ํฐํŠธ๋ฅผ ์ ์šฉํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ์ฝ”๋“œ๋„ ๊ธธ์–ด์ง€์ง€ ์•Š๊ณ  ๋ณด๊ธฐ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„ ๊ทธ๋ ‡๊ฒŒ ์ง„ํ–‰ ํ–ˆ์œผ๋‚˜ ๊ตฌ๋™ ํ™”๋ฉด์—์„œ๋Š” ๋’ค์ชฝ ๋ถ€๋ถ„์ด dynamic type ์ ์šฉ์ด ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค

๋ฆฌ๋ทฐ์–ด์—๊ฒŒ ๋ฌผ์–ด๋ณด๋‹ˆ attributedText๊ฐ€ ์ ์šฉ๋˜๋Š” ์‹œ์ ์— ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ž์˜ ์Šคํƒ€์ผ ์ •๋ณด๋กœ UILabel์˜ ์Šคํƒ€์ผ ๊ด€๋ จ ํ”„๋กœํผํ‹ฐ๋“ค์„ ์—…๋ฐ์ดํŠธ ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค! ๋ผ๋Š” ๋ง๋กœ ๋ฏธ๋ฃจ์–ด ๋ณด์•„ ์ ์šฉ๋˜๋Š” ๋ฒ”์œ„ ์ดํ›„์˜ ๋ฌธ์ž ์Šคํƒ€์ผ์€ ์ ์šฉ์ด ๋˜์ง€ ์•Š์•„ ์œ„์™€ ๊ฐ™์€ ํ˜„์ƒ์ด ์ผ์–ด๋‚œ ๊ฒƒ ๊ฐ™๋‹ค

7. ๊ฐ€๋กœ์ผ ๋•Œ ํšŒ์ „

์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ๋ฅผ ๊ฐ€๋กœ๋กœ ๋‘๊ณ  ์–ดํ”Œ์„ ์‹คํ–‰์‹œํ‚ค๋ฉด 2๋ฒˆ ํ™”๋ฉด์œผ๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ ํ™”๋ฉด ํšŒ์ „์ด ์ผ์–ด๋‚˜์ง€ ์•Š์Œ

-> ์ตœ์ดˆ ์‹คํ–‰์‹œ ๊ธฐ๊ธฐ์˜ ๋ฐฉํ–ฅ์ด ๋ณ€๊ฒฝ๋˜๊ธฐ ์ „์—๋Š” unknown์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ ๊ธฐ๊ธฐ์˜ ํ™”๋ฉด ์ƒํƒœ๋ฅผ ์ฒดํฌํ•ด์ฃผ๋Š” ๋กœ์ง์„ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๋ฐ ์–ดํ”Œ ์‚ฌ์šฉ์—๋Š” ํฐ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์•„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์Œ

โœ…

๋ฐฐ์šด ๊ฐœ๋…

  • ์˜์กด์„ฑ
  • ViewController์˜ init
  • dynamic type
  • NSMutableAttributedString

commit rule

์ปค๋ฐ‹ ์ œ๋ชฉ์€ ์ตœ๋Œ€ 50์ž ์ž…๋ ฅ ๋ณธ๋ฌธ์€ ์ตœ๋Œ€ 72์ž ํ•œ๊ธ€๋กœ ์ž…๋ ฅ

๐Ÿ’Žfeat : ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ๊ตฌํ˜„

โœ๏ธchore : ์‚ฌ์†Œํ•œ ์ฝ”๋“œ ์ˆ˜์ •, ๋‚ด๋ถ€ ํŒŒ์ผ ์ˆ˜์ •, ํŒŒ์ผ ์ด๋™ ๋“ฑ

๐Ÿ”จfix : ๋ฒ„๊ทธ, ์˜ค๋ฅ˜ ํ•ด๊ฒฐ

๐Ÿ“docs : README๋‚˜ WIKI ๋“ฑ์˜ ๋ฌธ์„œ ๊ฐœ์ •

โ™ป๏ธrefactor : ์ˆ˜์ •์ด ์žˆ์„ ๋•Œ ์‚ฌ์šฉ (์ด๋ฆ„๋ณ€๊ฒฝ, ์ฝ”๋“œ ์Šคํƒ€์ผ ๋ณ€๊ฒฝ ๋“ฑ)

โšฐ๏ธdel : ์“ธ๋ชจ์—†๋Š” ์ฝ”๋“œ ์‚ญ์ œ

๐Ÿ”ฌtest : ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ˆ˜์ •

๐Ÿ“ฑstoryboard : ์Šคํ† ๋ฆฌ ๋ณด๋“œ๋ฅผ ์ˆ˜์ • ํ–ˆ์„ ๋•Œ

About

๐Ÿป iOS ์ปค๋ฆฌ์–ด ์Šคํƒ€ํ„ฐ ์บ ํ”„ ๐ŸŒƒ ๋งŒ๊ตญ ๋ฐ•๋žŒํšŒ

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 100.0%