Jiseob Kim

iOS Developer

Swift - Generic & Codable

19 Aug 2018 » Swift

์•ž์„  ํฌ์ŠคํŒ…๊ธ€๋“ค์˜ ์ข…ํ•ฉํŒ!!


์•ž์„œ ํฌ์ŠคํŒ…ํ•œ๊ฒƒ๋“ค์„ ๋‚˜์—ดํ•ด๋ณด๋ฉด

  1. Alamofire: ํ†ต์‹ ์„ ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  2. Codable: Swift4๋ถ€ํ„ฐ ์ƒ๊ธด๊ฒƒ์œผ๋กœ JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐ์ฒด๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ต‰์žฅํžˆ ์ข‹์€ ํ”„๋กœํ† ์ฝœ
  3. Escaping: ๋น„๋™๊ธฐ์‹ ํ•จ์ˆ˜(ex: Alamofire)๋ผ ๋ถˆ๊ฐ€๋Šฅํ–ˆ๋˜ return๊ฐ’ ์ฒ˜๋ฆฌ๋ฅผ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ•

ํฌ๊ฒŒ ์ด๋ ‡๊ฒŒ 3๊ฐ€์ง€์˜ ์ฃผ์ œ๋กœ ์ง„ํ–‰ ๋˜์—ˆ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ์— ํ•˜๊ฒŒ๋  ๊ฒƒ์€ ์ด๊ฒƒ๋“ค์˜ ์ข…ํ•ฉํŒ์ด๋ผ ์ƒ๊ฐํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

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

๊ทธ๋ž˜์„œ ์–ด๋–ป๊ฒŒํ•˜๋ฉด ๋ฐ˜๋ณต์„ ์ค„์ผ๊นŒ?๋กœ ์‹œ์ž‘ํ•ด์„œ Codable, Escaping, Generic ๋“ฑ๋“ฑ์„ ์ตํ˜€๊ฐ€๋ฉด์„œ ์ ์šฉํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ตœ์ข…์  ๋ชฉํ‘œ๋Š” ๋ฐ˜๋ณต์„ ์ค„์—ฌ ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ ์ค„์ด๊ณ  ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค๊ธฐ ์ด๊ฒƒ์ด ๋ชฉํ‘œ์ž…๋‹ˆ๋‹ค

Q. ๊ฐ€์ •

์—ฌํƒœ๊ป ํ–ˆ๋˜๊ฒƒ์œผ๋กœ๋„ ์ถฉ๋ถ„ํžˆ ์‹œ๊ฐ„๊ณผ ์ฝ”๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ! Codable์„ ์‚ฌ์šฉํ•  ํ˜•ํƒœ๊ฐ€ ๋งŽ์•„์ง„๋‹ค๋ฉด? ๋ณต์žกํ•ด์งˆ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ์„  ๊ตฌ์กฐ์ฒด 1๊ฐœ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

struct StructA: Codable {
    var hp: String?
    var name: String?
    var age: Int?
}

์ด 3๊ฐœ์˜ ๊ตฌ์กฐ์ธ๋ฐ์š”, ์•ž์„œ ํฌ์ŠคํŒ… ํ–ˆ๋˜ Codable๊ณผ Escaping์„ ์ด์šฉํ•œ๋‹ค๋ฉด Alamofire๋ฅผ ํ†ตํ•ด ์–ป์€ ์‘๋‹ต๊ฐ’์„ ์‰ฝ๊ฒŒ ํ•ด๋‹น ๊ตฌ์กฐ์ฒด์˜ ๊ฐ์ฒด๋ฅผ ์–ป์–ด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๊ฐ€์ •์„ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

struct StructA: Codable {
    var hp: String?
    var name: String?
    var age: Int?
}

struct StructB: Codable {
    var country: String?
    var address: String?
}

struct StructC: Codable {
    var data1: StructA?
    var data2: StructB?
}

์ด๋ฒˆ์—” ๊ตฌ์กฐ์ฒด๊ฐ€ 3๊ฐœ ์ž…๋‹ˆ๋‹ค. URL๋„ 3๊ฐœ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ ์ž…๋‹ˆ๋‹ค! ๊ทธ๋ ‡๋‹ด ์—ฌ๊ธฐ์„œ Codable / Escaping / Alamofire๋ฅผ ๋˜‘๊ฐ™์ด ์ด์šฉํ•˜๋ ค๋ฉด 3๊ฐ€์ง€์˜ Decodable ํ•จ์ˆ˜๊ฐ€ ์žˆ์–ด์•ผ ํ• ๊นŒ์š”?

๋„ค ์žˆ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค.

Generic์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ง์ด์ฃ .

Generic

์˜์–ด ์‚ฌ์ „ generic

  1. ์ผ๋ฐ˜์ ์ธ
  2. ํฌ๊ด„์ ์ธ
  3. ์ด์นญ์ ์ธ

์ œ๋„ค๋ฆญ์€ ๋‹ค์†Œ ๋‚ฏ์„ค์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋„ ์ฑ…์—์„œ ๋ดค์ง€๋งŒ ์ฑ…์—์„œ ๋น„์ค‘๋„ ํฌ์ง€ ์•Š์•˜๊ณ , ์˜ˆ์‹œ๋Š” ์žˆ์—ˆ์œผ๋‚˜ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ• ์ง€ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค.

์˜์–ด์‚ฌ์ „์—์„œ 1๋ฒˆ์˜ ์˜๋ฏธ์™€ ๊ฐ™์ด ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ๋กœ ๋งŒ๋“ค์–ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ •๋„ ๋ง๋กœ๋Š” ์ดํ•ด๊ฐ€ ํž˜๋“ค๊ธฐ์— ์ฝ”๋“œ๋กœ ์„ค๋ช…์„ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์• ํ”Œ์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

// ๋‘ ์ˆซ์ž ๋ณ€๊ฒฝ
func swapTwoInts(_ v1: inout Int, _ v2: inout Int) {
    let temp = v1
    v1 = v2
    v2 = temp
}

var value1: Int = 10
var value2: Int = 20
print("value1 = \(value1), value2 = \(value2)")

// ํ•จ์ˆ˜ ํ˜ธ์ถœ
swapTwoInts(&value1, &value2)
print("value1 = \(value1), value2 = \(value2)")

์–ด๋ ต์ง€ ์•Š์€ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ๋‘๊ฐ€์ง€ ์ธ์ž๋ฅผ ๋„ฃ๊ณ  ์„œ๋กœ ๊ฐ’์„ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ฒƒ์ด๊ณ ,

ํ•จ์ˆ˜์ธ์ž ํƒ€์ž…์— inout์ด ๋ถ™์€ ์ด์œ ๋Š” ์™ธ๋ถ€์˜ ๋ณ€์ˆ˜๊ฐ’์„ ๋ฐ”๊ฟ”์ฃผ๊ธฐ ์œ„ํ•ด์„œ ์ž…๋‹ˆ๋‹ค. ๋ณดํ†ต์˜ ๊ฒฝ์šฐ ๊ฐ’์ด ๋ณต์‚ฌํ•ด์„œ ๋“ค์–ด๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜๋‚ด์—์„œ inout์ด ์—†๋‹ค๋ฉด v1๊ณผ v2์— ๊ฐ’์„ ํ• ๋‹นํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

inout์„ ์ ์šฉํ•ด์ค€๋‹ค๋ฉด ์ด๋ฅผ ๊ฐ€๋Šฅ์บํ•ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ฝ”๋“œ๋ณด๋ฉด &๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

c์–ธ์–ด๋ฅผ ๋ฐฐ์šฐ์…จ๋‹ค๋ฉด ํฌ์ธํ„ฐ ๋ถ€๋ถ„์—์„œ &๋ฅผ ์ด์šฉํ•˜์—ฌ ์ฃผ์†Œ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ƒ๊ฐ์ด ๋˜๋ฉฐ

์‹ค์ œ value1๊ณผ value2๊ฐ€ ์žˆ๋Š” ์ฃผ์†Œ ๊ฐ’์„ ํ•จ์ˆ˜์— ๋„ฃ๊ธฐ ๋•Œ๋ฌธ์— ํ•จ์ˆ˜์—์„œ ๊ฐ’ ๋ณ€๊ฒฝ์‹œ ์‹ค์ œ๋กœ ๋ณ€๊ฒฝ์ด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, Intํ˜•๋งŒ ํ•ด๋‹น์ด ๋˜๊ธฐ๋•Œ๋ฌธ์— String์ด๋‚˜ Double์ผ ๊ฒฝ์šฐ ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.

์˜ค๋ฒ„๋ผ์ด๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ชจ๋“  ํƒ€์ž…์— ํ•ด์•ผํ• ๊นŒ์š”? ๊ทธ๋Ÿฌ๋ฉด ๊ต‰์žฅํžˆ ๋ถˆํŽธํ• ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๋•Œ, Generic์ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

// ๋‘ ๋ณ€์ˆ˜๊ฐ’ ๊ตํ™˜
func swapTwoInts<T>(_ v1: inout T, _ v2: inout T) {
    let temp = v1
    v1 = v2
    v2 = temp
}

์—ฌ๊ธฐ์„œ T๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋Š”๋ฐ์š”, ๋‚ฏ์„ค์ˆ˜ ์žˆ์ง€๋งŒ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. T๋Š” ์ œ๊ฐ€ ์ž„์˜๋กœ ์ ์–ด์„œ ๋งŒ๋“  ์ œ๋„ค๋ฆญ ํƒ€์ž…๋ช…์ž…๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋Š”๊ฑด T๊ฐ€ ์•„๋‹ˆ๋ผ V๊ฐ€ ๋ ์ˆ˜๋„ ์žˆ๊ณ  Test๊ฐ€ ๋ ์ˆ˜๋„ ์žˆ๊ณ  ๋งˆ์Œ๋Œ€๋กœ ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ T๋ฅผ ์“ฐ๋Š”๊ฒƒ ๊ฐ™๋”๊ตฐ์š”.

Stringํ˜•๊ณผ Intํ˜•์„ ์ œ๋„ค๋ฆญ์„ ์ด์šฉํ•œ ํ•จ์ˆ˜ ํ•˜๋‚˜๋กœ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ ์ž…๋‹ˆ๋‹ค.

ํ•จ์ˆ˜ ํ•˜๋‚˜๋ฅผ ์ผ๋ฐ˜์ ์ธ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค! โ€˜์ผ๋ฐ˜์ ์ธ ํ˜•ํƒœ๋กœโ€™ ยซย โ€˜์ผ๋ฐ˜์ โ€™ ยซย โ€˜Generic!!โ€™ ํ›—

๊ทธ๋ ‡๋‹ค๋ฉด ์ดˆ๋ฐ˜์œผ๋กœ ๋Œ์•„๊ฐ€ ๊ฐ€์ •์ด์—ˆ๋˜, 3๊ฐ€์ง€ ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด๋ฅผ Codable์„ ์ด์šฉํ•˜์—ฌ ๊ฐ์ฒด๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํ•จ์ˆ˜๋ฅผ

3๊ฐœ ๋งŒ๋“œ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์ผ๋ฐ˜์ ์œผ๋กœ ์“ฐ์ผ ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•˜๋Š”๊ฒŒ ์ด ๊ธ€์˜ ์ตœ์ข… ๋ชฉ์ ์ž…๋‹ˆ๋‹ค.

Enum

์šฐ์„  enum์„ ์ด์šฉํ•ด url๋“ค์„ ์ •์˜ํ•˜๊ณ  ์ด๋ฅผ ์ด์šฉํ•˜๋Š” ํ•จ์ˆ˜๋„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

enum ListURL: String {
        case url1 = "http://localhost/Generic1.php"
        case url2 = "http://localhost/Generic2.php"
        case url3 = "http://localhost/Generic3.php"
        
        func alamofireDefault(handler: @escaping (NSDictionary?)->Void) {
            // url ์ •์˜
            let url = self
            // ํ†ต์‹  ์ง„ํ–‰
            let network = Alamofire.request(url.rawValue)
            // ํ†ต์‹  ์‘๋‹ต
            network.responseJSON { (response) in
                
                switch response.result {
                case .success(let object):
                    // NSDictionary ํ˜•ํƒœ๋กœ ๋ณ€๊ฒฝ
                    guard let nsDic = object as? NSDictionary else {
                        // ์บ์ŠคํŒ… ์‹คํŒจ
                        handler(nil)
                        return
                    }
                    // ์บ์ŠคํŒ… ์„ฑ๊ณต & ๋ฐ˜ํ™˜
                    handler(nsDic)
                    break
                    
                case .failure(let e):
                    // ํ†ต์‹  ์‹คํŒจ
                    print(e.localizedDescription)
                    handler(nil)
                }
            }
        }

    }

์•ž์„  ํฌ์ŠคํŒ…์˜ ๋Œ€๋ถ€๋ถ„์ด ์ €๊ธฐ์— ๋“ค์–ด๊ฐ€์žˆ์Šต๋‹ˆ๋‹ค. enum, Alamofire, Escaping!

Enum(์—ด๊ฑฐํ˜•)์˜ ์žฅ์ 

์„ ์–ธํ•œ ์ผ€์ด์Šค ์™ธ์—๋Š” ์ ์šฉ ๋ถˆ๊ฐ€๋Šฅ -> ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ ๋‚ฎ์ถค

์—ด๊ฑฐํ˜• ์•ˆ์— ๊ด€๋ จ ํ•จ์ˆ˜๋„ ๋งŒ๋“ค์–ด์คฌ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์€ ์–ด๋–ป๊ฒŒ ํ• ๊นŒ์š”?

// ์„ ์–ธ
let url: ListURL = .url1
// ListURL ์•ˆ์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ
url.alamofireDefault(type: StructA()) { (nsDic) in
    if let value = nsDic {
        print(value)
    }
}

๊ฒฐ๊ณผ๊ฐ’์„ ๋ณด๊ธฐ์ „์— ๊ฐ url์˜ JSON ํ˜•ํƒœ์˜ ์‘๋‹ต๊ฐ’๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค

//url1
{"hp":"01012341234","name":"KJS","age":27}

//url2
{"country":"Korea","address":"Seoul"}

//url3
{"data1":{"hp":"01012341234","name":"KJS","age":27},"data2":{"country":"Korea","address":"Seoul"}}

url3์˜ ๊ฒฝ์šฐ data1์—๋Š” url1์˜ ์‘๋‹ต๊ณผ ๊ฐ™์€ ๊ฐ’, data2์˜ ๊ฒฝ์šฐ๋Š” url2์˜ ์‘๋‹ต๊ฐ’๊ณผ ๊ฐ™์€ ๊ฐ’์ž…๋‹ˆ๋‹ค.

url1๋งŒ ๊ฒฐ๊ณผ๋Š” ์‰ฝ๊ฒŒ ๋‚˜์™”๊ตฌ์š”!

๊ทผ๋ฐ ์—ฌ๊ธฐ์„œ Codable์€ ์“ฐ์ง€ ์•Š๊ณ  NSDictionary ํ˜•ํƒœ๋กœ๋งŒ ์บ์ŠคํŒ…ํ›„ ๋Œ๋ ค์คฌ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์ด๋•Œ ์ƒํ™ฉ์— ๋”ฐ๋ผ Codable์„ ์ด์šฉํ• ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ์ „

// ์„ ์–ธ
let url: ListURL = .url1
// ListURL ์•ˆ์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ
url.alamofireDefault(type: StructA()) { (nsDic) in
    if let value = nsDic {
        print(value)
    }
}

๋ณ€๊ฒฝํ›„

let url: ListURL = .url1
        
        
url.alamofireDefault(type: StructA()) { (nsDic) in
    if let value = nsDic {
        do {
            // JSON์œผ๋กœ ๋ณ€ํ™˜
            let data = try JSONSerialization.data(withJSONObject: value, options: .prettyPrinted)
			// Decodable ์‚ฌ์šฉ
            let codableObject = try JSONDecoder().decode(StructA.self, from: data)
            print("""
                hp : \(codableObject.hp!)
                name : \(codableObject.name!)
                age : \(codableObject.age!)
                """)

        } catch {
            print(error.localizedDescription)
        }

    }
}

์ดํ•ด๊ฐ€ ์•ˆ๋œ๋‹ค๋ฉด ์•„๋ž˜ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”

์ฐธ๊ณ  : Alamofire์™€ Codable

์ดํ•ด๊ฐ€ ๋๋‹จ ๊ฐ€์ •ํ•˜์— ํฌ์ธํŠธ๋Š” Decodable ์‚ฌ์šฉ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค

decodeํ•จ์ˆ˜์˜ ์ธ์ž๊ฐ€ 2๊ฐ€์ง€ ์ž…๋‹ˆ๋‹ค. Decodableํ”„๋กœํ† ์ฝœ๊ณผ ๋ฐ์ดํƒ€

์—ฌ๊ธฐ์„œ from๋ถ€๋ถ„์€ JSON๋ณ€ํ™˜๋œ ๋ฐ์ดํ„ฐ๋‹ˆ ๊ณตํ†ต ์‚ฌ์šฉ์ด ๋˜์ง€๋งŒ, ์ฒซ๋ฒˆ์งธ ์ธ์ž์˜ ๊ฒฝ์šฐ๋Š” ์‚ฌ์šฉ์ด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ํ•จ์ˆ˜๋กœ ๋ฐ”๊ฟ”๋„ ๊ต‰์žฅํžˆ ๋‚œ๊ฐํ• ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์œ„ GenericํŒŒํŠธ ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ์‚ฌ์šฉ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

GenericํŒŒํŠธ์—์„œ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๊ฒƒ์ฒ˜๋Ÿผ ์—ฌ๊ธฐ์„œ๋„ Generic์„ ์ด์šฉํ•ด๋ด…์‹œ๋‹ค.

ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

func useDecodable<T>(type: T, nsDic: NSDictionary) -> T? {
    // JSON ๋ณ€ํ™˜
    do {
        // JSON ๋ณ€ํ™˜
        let JSONData = try JSONSerialization.data(withJSONObject: nsDic, options: .prettyPrinted)
        // Decodable์„ ์ด์šฉํ•ด ๊ฐ์ฒด๋ฅผ ์–ป์Œ
        let data = try JSONDecoder().decode(T.self, from: JSONData)
        // data ๋Œ๋ ค์ฃผ๊ธฐ
        return data
    } catch {
        // ์—๋Ÿฌ์‹œ ์ถœ๋ ฅ
        print(error.localizedDescription)
        // nil๋Œ๋ ค์ฃผ๊ธฐ
        return nil
    }
}

T๋ผ๋Š” ํƒ€์ž…์„ ์ œ๋„ค๋ฆญ ํƒ€์ž…์„ ๋งŒ๋“ค์—ˆ๊ณ  ๋ฌธ์ œ๊ฐ€ ๋˜์—ˆ๋˜ decode์ชฝ์„ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค

// ์ผ๋ฐ˜์ ์ธ ํƒ€์ž…์„ ๋„ฃ์Œ T.self
let data = try JSONDecoder().decode(T.self, from: JSONData)

์œ„์™€ ๊ฐ™์ด ์ผ๋ฐ˜์ ์ธ ํƒ€์ž…์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

( ์ฃผ์˜ !! ์ด ๋ฐฉ์‹์˜ ๋‹จ์ ์€ type์ด๋ผ๋Š” ์ธ์ž๋Š” ํƒ€์ž…๋งŒ ์ฃผ๊ธฐ์œ„ํ•ด ๊ฐ€์ ธ์˜ฌ๋ฟ ์‹ค์ œ๋กœ ์‚ฌ์šฉ์ด ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. )

์‹คํ–‰์ด ๋ ๊นŒ์š”?

๋„ค ์•ˆ๋ฉ๋‹ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” ๋ญ˜๊นŒ์š”? ๊ฒฐ๋ก ์„ ์–˜๊ธฐํ•˜๋ฉด ์ œ๋„ค๋ฆญ ํƒ€์ž…์ธ T๋Š” Decodable ํ”„๋กœํ† ์ฝœ์ด ์—†๋‹ค๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค.

์ œ๋„ค๋ฆญ T์— ํ”„๋กœํ† ์ฝœ์„ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ

func useDecodable<T: Codable>(type: T, nsDic: NSDictionary) -> T? {}

ํ•จ์ˆ˜๋ช… ์˜†์— ์žˆ๋˜ T ํ™”์‚ดํ‘œ๊ด„ํ˜ธ ์•ˆ์— ์œ„์™€ ๊ฐ™์ด ์ •์˜ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋ณต๋ถ™์„ ํ•  ๋ˆ„๊ตฐ๊ฐ€ ์žˆ์„์ง„ ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ํŽธ์˜๋ฅผ ์œ„ํ•ด ํ’€์ฝ”๋“œ!

func useDecodable<T: Codable>(type: T, nsDic: NSDictionary) -> T? {
    // JSON ๋ณ€ํ™˜
    do {
        // JSON ๋ณ€ํ™˜
        let JSONData = try JSONSerialization.data(withJSONObject: nsDic, options: .prettyPrinted)
        // Decodable์„ ์ด์šฉํ•ด ๊ฐ์ฒด๋ฅผ ์–ป์Œ
        let data = try JSONDecoder().decode(T.self, from: JSONData)
        return data
    } catch {
        print(error.localizedDescription)
        return nil
    }
}

์—๋Ÿฌ๋Š” ์‚ฌ๋ผ์กŒ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ์‚ฌ์šฉ๋ฒ•์ชฝ์œผ๋กœ ๊ฐ€์„œ

๋ณ€๊ฒฝ์ „

// ์„ ์–ธ
let url: ListURL = .url1
// ListURL ์•ˆ์˜ ํ•จ์ˆ˜ ํ˜ธ์ถœ
url.alamofireDefault(type: StructA()) { (nsDic) in
    if let value = nsDic {
        print(value)
    }
}

๋ณ€๊ฒฝํ›„

let url: ListURL = .url1
        
url.alamofireDefault(type: StructA()) { (nsDic) in
    if let value = nsDic {

        switch url {
        case .url1:
            let object = self.useDecodable(type: StructA(), nsDic: value)
            print(object!)
        case .url2:
            let object = self.useDecodable(type: StructB(), nsDic: value)
            print(object!)
        case .url3:
            let object = self.useDecodable(type: StructC(), nsDic: value)
            print(object!)
        }

    }
}

switch๋ฅผ ์ด์šฉํ•ด ๊ฒฝ์šฐ๋ฅผ ๋‚˜๋ˆ„์—ˆ๊ณ , ์ด๋Š” ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด ๋‹ค ์ผ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅด๊ฒŒ ์œ ๋™์ ์œผ๋กœ ํ™œ์šฉํ•˜๋ฉด ์ข‹์„๊ฒƒ์ž…๋‹ˆ๋‹ค!

์ง€๊ธˆ ์ € ์ƒํƒœ๋Š” ๋‹จ์ˆœํžˆ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค~!

ํฌ์ธํŠธ๋Š”!! ํ•จ์ˆ˜ ํ•œ๊ฐ€์ง€๋ฅผ ๊ฐ€์ง€๊ณ  ์„œ๋กœ ๋‹ค๋ฅธ ๊ตฌ์กฐ์ฒด์ผ์ง€๋ผ๋„ Codable์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ๋Š” ์ € ํ•จ์ˆ˜๋งŒ ํ•„์š”ํ• ๋•Œ ๋”ฐ๋กœ ์‚ฌ์šฉ์„ ํ•˜๊ฒ ์ฃ ?

๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด

URL 1์˜ ๊ฒฝ์šฐ

URL 2์˜ ๊ฒฝ์šฐ

URL 3์˜ ๊ฒฝ์šฐ

๋ชจ๋‘ ์ž˜๋‚˜์™”์ฃ ???

์ € ๊ฐ™์€ ๊ฒฝ์šฐ ์ด๋Ÿฐ๊ฒƒ์„ ์ด์šฉํ•ด์„œ ์ข€ ๋” ํŽธํ•˜๊ฒŒ ์‹ค์ œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! ์ข€๋” ํŽธํ•œ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„ ๋ฐœ๊ฒฌํ•˜๋ฉด ํฌ์ŠคํŒ… ํ•ด์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋กœ์จ Alamofire, Codable, Escaping, Generic์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•œ ์ด๋ฒˆ ํฌ์ŠคํŒ…์„ ๋งˆ์นฉ๋‹ˆ๋‹ค!