[Swift] load(_:) method (fetching JSON data) ๋œฏ์–ด๋ณด๊ธฐ

    import Foundation
    
    //Create an array of landmarks that you initialize from landmarkData.json.
    var landmarks: [Landmark] = load("landmarkData.json")
    
    func load<T: Decodable>(_ filename: String) -> T {
        let data: Data
    
        guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
        else {
            fatalError("Couldn't find \(filename) in main bundle.")
        }
    
         do {
            // Data(contentsOf:) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ Data ๊ฐ์ฒด๋กœ ์ฝ์–ด์˜จ๋‹ค. 
            // ํŒŒ์ผ์„ ์ฝ๋Š” ๊ณผ์ •์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ try-catch ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค. 
            // ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ, fatalError๋ฅผ ํ†ตํ•ด ํ”„๋กœ๊ทธ๋žจ์„ ์ค‘์ง€ํ•˜๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.
            data = try Data(contentsOf: file)
        } catch {
            fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
        }
    
        do {
            // JSONDecoder ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ , decode(_:from:) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋””์ฝ”๋”ฉํ•œ๋‹ค. 
            // ๋””์ฝ”๋”ฉํ•  ํƒ€์ž…์€ T.self๋กœ ์ „๋‹ฌ๋˜๋ฉฐ, ์ด๋Š” ์ œ๋„ค๋ฆญ์œผ๋กœ ์ „๋‹ฌ๋ฐ›์€ ํƒ€์ž… T์˜ ์‹ค์ œ ํƒ€์ž…์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค. 
            // ๋””์ฝ”๋”ฉ ๊ณผ์ •์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ try-catch ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค. 
            // ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ, fatalError๋ฅผ ํ†ตํ•ด ํ”„๋กœ๊ทธ๋žจ์„ ์ค‘์ง€ํ•˜๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. 
            // ๋””์ฝ”๋”ฉ์ด ์„ฑ๊ณตํ•˜๋ฉด ๋””์ฝ”๋”ฉ๋œ ๊ฐ’์ธ T๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
            let decoder = JSONDecoder()
            return try decoder.decode(T.self, from: data)
        } catch {
            fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
        }
    
    }

     

    ์œ„์˜ ์ฝ”๋“œ๋Š” ์ œ๋„ค๋ฆญ ํ•จ์ˆ˜์ธ load๋ฅผ ์ •์˜ํ•˜๊ณ  ์žˆ๋‹ค.  ํŒŒ์ผ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๊ณ , ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์ •๋œ ํƒ€์ž…์œผ๋กœ ๋””์ฝ”๋”ฉํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค!  Decodable ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๋Š” ๊ตฌ์กฐ์ฒด ๋˜๋Š” ํด๋ž˜์Šค ํƒ€์ž…์„ ์ง€์ •ํ•˜์—ฌ load ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด, ํ•ด๋‹น ํŒŒ์ผ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋””์ฝ”๋”ฉ๋˜์–ด ํ•ด๋‹น ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค๋กœ ๋ฐ˜ํ™˜๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด JSON ๋ฐ์ดํ„ฐ๋ฅผ Swift ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    file ๋ณ€์ˆ˜๋ฅผ ์˜ต์…”๋„ ๋ฐ”์ธ๋”ฉ →  ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๊ฐ€ nil์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ file์— ๊ฐ’์ด ํ• ๋‹น → ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ Data ๊ฐ์ฒด๋กœ ์ฝ์–ด์˜ค๊ธฐ →  JSONDecoder ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ →  decode(_:from:) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋””์ฝ”๋”ฉ

     

     


    ๐Ÿค” ์ œ๋„ค๋ฆญ ํƒ€์ž… T?

    ์ œ๋„ค๋ฆญ ํƒ€์ž… T๋Š” ํ•จ์ˆ˜๋‚˜ ํƒ€์ž…์„ ์ •์˜ํ•  ๋•Œ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋  ํƒ€์ž…์„ ๋‚˜ํƒ€๋‚ด๋Š” ์ผ์ข…์˜ ํ”Œ๋ ˆ์ด์Šคํ™€๋”
    T๋Š” ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ์„œ, ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์‹ค์ œ ํƒ€์ž…์œผ๋กœ ๋Œ€์ฒด๋œ๋‹ค.

    ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋‚˜ ํƒ€์ž…์„ ์ •์˜ํ•˜๋ฉด, ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ํƒ€์ž…์— ๋Œ€ํ•ด ๋™์ž‘ํ•˜๋Š” ์œ ์—ฐํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•จ์ˆ˜๋‚˜ ํƒ€์ž…์„ ์ผ๋ฐ˜ํ™”ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‹ค์–‘ํ•œ ํƒ€์ž…์— ๋Œ€ํ•ด ๋™์ผํ•œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์œ„์˜ ์ฝ”๋“œ์—์„œ load ํ•จ์ˆ˜๋Š” T๋ผ๋Š” ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ๋ฐ›๋Š”๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ T์—๋Š” ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ํƒ€์ž…์ด ์ง€์ •๋œ๋‹ค.
    ์˜ˆ๋ฅผ ๋“ค์–ด, load<Landmark>("landmarks.json")์™€ ๊ฐ™์ด ํ˜ธ์ถœํ•˜๋ฉด T๋Š” Landmark ํƒ€์ž…์œผ๋กœ ๋Œ€์ฒด๋œ๋‹ค.

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

     

    ๐Ÿค” filename ์•ž์— ๋ถ™๋Š” '_' ๋Š” ๋ญ˜๊นŒ? 

    `load` ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ `filename` ์•ž์— ๋ถ™์€ `_`๋Š” ์™€์ผ๋“œ์นด๋“œ ์‹๋ณ„์ž์ž…๋‹ˆ๋‹ค. ์™€์ผ๋“œ์นด๋“œ ์‹๋ณ„์ž๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์ƒ๋žตํ•˜๊ณ ์ž ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

    `load` ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ๋  ๋•Œ ํŒŒ์ผ ์ด๋ฆ„์„ ์ธ์ž๋กœ ์ „๋‹ฌ๋ฐ›์•„์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•จ์ˆ˜ ๋‚ด์—์„œ๋Š” `filename`์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ, ํ•จ์ˆ˜ ํ˜ธ์ถœ์ž์—๊ฒŒ ํŒŒ์ผ ์ด๋ฆ„์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

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

    ๋”ฐ๋ผ์„œ, `func load<T: Decodable>(_ filename: String)`์€ ๋งค๊ฐœ๋ณ€์ˆ˜ `filename`์„ ๊ฐ€์ง€์ง€๋งŒ, ํ˜ธ์ถœ ์‹œ์—๋Š” ํŒŒ์ผ ์ด๋ฆ„๋งŒ ์ „๋‹ฌํ•˜๋ฉด ๋œ๋‹ค. `_`๋Š” ํ˜ธ์ถœ์ž์—๊ฒŒ ํ•ด๋‹น ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์„ ๊ฐ์ถ”๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํ‘œ๊ธฐ๋ฒ•์ด๋‹ค.


    +) ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์ด๋ฆ„์„ ๊ฐ์ถ”์ง€ ์•Š์„ ๊ฒฝ์šฐ ์ฝ”๋“œ์˜ ๋ชจ์Šต
    let result: MyType = load<MyType>(filename: "data.json")โ€‹

     

    ๐Ÿค” guard๋Š” ๋ญ์ง€?

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

     

      guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
        else {
            fatalError("Couldn't find \(filename) in main bundle.")
        }
    ์œ„์˜ ์ฝ”๋“œ๋Š” guard ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ Bundle.main.url(forResource:withExtension:) ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๊ณ , ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ fatalError๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ฝ”๋“œ์ด๋‹ค.

    Bundle.main.url(forResource:withExtension:) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํŒŒ์ผ์˜ URL์„ ๊ฐ€์ ธ์˜จ๋‹ค. ์ด๋•Œ filename์„ ํŒŒ์ผ ์ด๋ฆ„์œผ๋กœ ์ „๋‹ฌํ•˜๊ณ , withExtension์€ ํŒŒ์ผ์˜ ํ™•์žฅ์ž๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”๋ฐ, nil๋กœ ์ „๋‹ฌ๋˜์–ด ํ™•์žฅ์ž๋ฅผ ์ƒ๋žตํ•จ์„ ์˜๋ฏธํ•œ๋‹ค.

    guard ๊ตฌ๋ฌธ์˜ ์กฐ๊ฑด์—์„œ๋Š” file ๋ณ€์ˆ˜๋ฅผ ์˜ต์…”๋„ ๋ฐ”์ธ๋”ฉํ•œ๋‹ค. Bundle.main.url(forResource:withExtension:) ๋ฉ”์„œ๋“œ์˜ ๊ฒฐ๊ณผ๊ฐ€ nil์ด ์•„๋‹Œ ๊ฒฝ์šฐ์—๋งŒ file์— ๊ฐ’์ด ํ• ๋‹น๋˜๊ณ , ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ else ๋ธ”๋ก์ด ์‹คํ–‰๋œ๋‹ค.

    else ๋ธ”๋ก ๋‚ด๋ถ€์—์„œ๋Š” fatalError๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ํ”„๋กœ๊ทธ๋žจ์„ ์ค‘์ง€์‹œํ‚จ๋‹ค. fatalError ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ฆ‰์‹œ ์ข…๋ฃŒ๋˜๋ฉฐ, ์ดํ›„์˜ ์ฝ”๋“œ๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

    ์ฆ‰, ์œ„์˜ ์ฝ”๋“œ๋Š” ํŒŒ์ผ์˜ URL์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ณผ์ •์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ, ํ”„๋กœ๊ทธ๋žจ์„ ์ค‘์ง€ํ•˜๊ณ  ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์„ ๋ชฉ์ ์œผ๋กœ ํ•œ๋‹ค. ์ด๋Š” ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ์ƒํ™ฉ ๋“ฑ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์˜ค๋ฅ˜์— ๋Œ€๋น„ํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์˜ ์•ˆ์ •์„ฑ์„ ๋†’์ด๋Š”๋ฐ ๋„์›€์„ ์ค€๋‹ค.

     



    ๋ฐ˜์‘ํ˜•

    ๋Œ“๊ธ€