๐ŸŽ iOS & Swift

[iOS] URLSession(1) - ๊ธฐ๋ณธ ํ๋ฆ„

taeeekki 2022. 8. 30. 13:07

URLSession

์•„๋ž˜ 3๊ฐ€์ง€๋ฅผ ์ž˜ ๊ธฐ์–ตํ•ด๋ณด์ž

 

- URLSession

- URLSessionDataTask

- Response, CompletionHandler

 


URLSessionDataTask

- ์š”์ฒญ์„ ํ•˜๋Š” ํ•˜๋‚˜ํ•˜๋‚˜(Task)

- ์ผ๋ฐ˜ ํ†ต์‹ , ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋‹ค์šด๋กœ๋“œ, ์‹œํฌ๋ฆฟ ๋ชจ๋“œ ๋“ฑ ๋ชฉ์ ์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ Task๋กœ ์ข…๋ฅ˜๊ฐ€ ๋‚˜๋‰œ๋‹ค.

 


URLSessionDelegate

- + å๋กœ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

- ์ค‘๊ฐ„ ์ค‘๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์–ผ๋งˆ๋‚˜ ๋ฐ›์•„์™”๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

- ex. ์นด์นด์˜คํ†ก ์‚ฌ์ง„ 10์žฅ ํ•œ ๋ฒˆ์— ์ €์žฅ (๋‹ค์šด๋กœ๋“œ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•œ ์žฅ์”ฉ ๋‹ค์šด๋กœ๋“œ ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.)

- ์ผ๋ฐ˜ ํ†ต์‹ ์—์„œ๋Š” ์†๋„๊ฐ€ ๊ต‰์žฅํžˆ ๋น ๋ฅธ ํŽธ์ด๊ธฐ ๋•Œ๋ฌธ์— Delegate๊นŒ์ง€ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

 


URLSession ์‚ฌ์šฉํ•˜๊ธฐ

Session

์• ํ”Œ์ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ ์‚ฌ์šฉ, ์ผ๋ฐ˜์ ์ธ ์š”์ฒญ โžก๏ธ shared(Singleton Session) ์‚ฌ์šฉ

์ข€ ๋” ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•˜๊ฒŒ ์‚ฌ์šฉ โžก๏ธ ์ƒ์„ฑ์ž ์‚ฌ์šฉ

 

(1) shared

- ๊ธฐ๋ณธ ์„ธ์…˜

- ๋‹จ์ˆœ, ์ปค์Šคํ…€ ๋ถˆ๊ฐ€, ์‘๋‹ต์€ ํด๋กœ์ € ํ˜•ํƒœ๋กœ ์ „๋‹ฌ, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ํ˜•ํƒœ๋Š” ์ฒ˜๋ฆฌ ๋ถˆ๊ฐ€

 

(2) init(configuration: _)

- default : shared์™€ ์œ ์‚ฌ, ์ปค์Šคํ…€์ด ๊ฐ€๋Šฅํ•˜๊ณ , ์‘๋‹ต์„ ํด๋กœ์ € ๋˜๋Š” Delegate ํ˜•ํƒœ๋กœ ํ•  ์ˆ˜ ์žˆ์Œ

- ephemeral : ์ •๋ณด๋ฅผ ํœ˜๋ฐœ์‹œํ‚ค๊ณ ์ž ํ•  ๋•Œ ์‚ฌ์šฉ

- background : ์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ์„ ์“ฐ๊ณ  ์žˆ์ง€ ์•Š์„ ๋•Œ ์–ด๋–ค ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ (ex. ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์žฌ์ƒ)

 

 


 

DataTask

- resume ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜๋“œ์‹œ ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผ ์‹คํ–‰๋œ๋‹ค.

- ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์—์„œ ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ UI ๊ด€๋ จ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋กœ ์ „ํ™˜ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

- ์•„์˜ˆ ๊ตฌํ˜„๋ถ€์—์„œ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ธฐ๋„ ํ•œ๋‹ค.

let url = URL(string: "")!

URLSession.shared.dataTask(with: url) { data, response, error in

    // ์•„์˜ˆ ๊ตฌํ˜„๋ถ€์—์„œ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ฃผ๊ธฐ๋„ ํ•œ๋‹ค.
    DispatchQueue.main.async {
        guard error == nil else {
            completion(nil, .failedRequest)
            return
        }

        guard let data = data else {
            completion(nil, .noData)
            return
        }

        // HTTPURLResponse๋กœ ํƒ€์ž… ์บ์ŠคํŒ…
        // URLResponse > HTTPURLResponse๋Š” ์ƒ์† ๊ด€๊ณ„
        guard let response = response as? HTTPURLResponse else {
            completion(nil, .invaildResponse)
            return
        }

        guard response.statusCode == 200 else {
            completion(nil, .failedRequest)
            return
        }

        do {
            let result = try JSONDecoder().decode(Lotto.self, from: data)
            completion(result, nil)

        } catch {
            completion(nil, .invaildData)
        }
    }

}.resume()

Completion์˜ ์ธ์ž๋กœ๋Š” Data์™€ Error๋ฅผ ๋„˜๊ฒจ์ฃผ๊ฒŒ ๋œ๋‹ค. ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์„ฑ๊ณตํ• ์ˆ˜๋„ ์žˆ๊ณ  ์‹คํŒจํ• ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ๊ฐ ์˜ต์…”๋„ ํƒ€์ž…์ด ๋˜๊ณ  nil๊ฐ’์„ ์ „๋‹ฌํ•˜๊ฒŒ ๋œ๋‹ค. ๊ฐ๊ฐ์˜ ๊ฒฝ์šฐ์— ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋ฉด์„œ nil๊ฐ’์„ ๋„˜๊ฒจ์ฃผ๋Š” ์ž‘์—…์ด ์ƒ๋‹นํžˆ ๊ท€์ฐฎ๊ธฐ ๋•Œ๋ฌธ์— Result๋ผ๋Š” ํƒ€์ž…์ด ๋“ฑ์žฅํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ ์ด ๋˜ํ•œ ๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ์ฑ…์ด ๋˜์ง€ ๋ชปํ•ด์„œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ์ข€ ๋” ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ทธ ํ๋ฆ„์ด ์ž์—ฐ์Šค๋Ÿฌ์šด async, await API๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

 


์‚ฌ์šฉ ํ๋ฆ„

 

์ง์ ‘ ๋„คํŠธ์›Œํฌ ํ†ต์‹  ์ฝ”๋“œ๋ฅผ viewDidLoad๋‚˜ controller ๋‹จ์—์„œ ์ž‘์„ฑํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ ์ฝ”๋“œ๋ฅผ ๋ฉ”์„œ๋“œ๋กœ ๊ฐ์‹ธ๋†“๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌํ˜„๋ถ€์™€ ํ˜ธ์ถœ๋ถ€๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค.

 

๋„คํŠธ์›Œํฌ ๋งค๋‹ˆ์ € ์ฝ”๋“œ (๊ตฌํ˜„๋ถ€)

final class PersonAPIManager {
    
    static func requestPerson(query: String, completion: @escaping ((Person?, APIError?) -> Void)) {

        let url = URL(string: "https://api.themoviedb.org/3/search/person?api_key=APIKEY&language=en-US&query=\(query)&page=1&include_adult=false&region=ko-KR")!
        
        URLSession.shared.dataTask(with: component.url!) { data, response, error in
            
            DispatchQueue.main.async {
                guard error == nil else {
                    completion(nil, .failedRequest)
                    return
                }
                
                guard let data = data else {
                    completion(nil, .noData)
                    return
                }

                guard let response = response as? HTTPURLResponse else {
                    completion(nil, .invaildResponse)
                    return
                }
                
                guard response.statusCode == 200 else {
                    completion(nil, .failedRequest)
                    return
                }
                
                do {
                    let result = try JSONDecoder().decode(Person.self, from: data)
                    completion(result, nil)
                    
                } catch {
                    completion(nil, .invaildData)
                }
            }

        }.resume()
        
    }
}

 

ํ˜ธ์ถœ๋ถ€

Controller์—์„œ ํ˜ธ์ถœ

PersonAPIManager.requestPerson(query: "Squid") { person, error in
    guard let person = person else { return }
    self.list = person
    self.tableView.reloadData()
}

 


 

์ •๋ฆฌ

URLSession ๊ตฌ์กฐ ๋ฐ ํ๋ฆ„