-Today's Learning Content-

  • JSON
  • API
  • Swift Network

๐Ÿ“Œ 1. ๋„คํŠธ์›Œํฌ ๊ธฐ๋ณธ ๊ฐœ๋…

๊ฐœ๋… ์ •๋ฆฌ

Swift์—์„œ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์€ ์•ฑ๊ณผ ์„œ๋ฒ„ ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ์ž‘์—…์„ ์˜๋ฏธํ•œ๋‹ค. ์ฃผ๋กœ URLSession์„ ์‚ฌ์šฉํ•ด HTTP ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์„ ๋ฐ›์•„ JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ์ด๋ฏธ์ง€, ํŒŒ์ผ ๋“ฑ์„ ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋œ๋‹ค.

1) JSON์€ ๋ˆ„๊ตฌ?

JSONJavaScript Object Notation)์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒฝ๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ ํฌ๋งท์ด๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ๊ตํ™˜์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.

  • ํŠน์ง•:

    • ์‚ฌ๋žŒ์ด ์ฝ๊ณ  ์“ฐ๊ธฐ ์‰ฝ๋‹ค.
    • ์ปดํ“จํ„ฐ๊ฐ€ ์‰ฝ๊ฒŒ ํŒŒ์‹ฑํ•˜๊ณ  ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ฃผ๋กœ Key-Value ์˜ ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค.
  • JSON ์˜ˆ์‹œ:

{
  "name": "John",
  "age": 25,
}

2) API๋ž€

APIApplication Programming Interface)๋Š” ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ์„œ๋กœ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ์ค‘๊ฐ„ ๋งค๊ฐœ์ฒด๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๊ฐ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค.

์‹ค์ƒํ™œ ์˜ˆ์‹œ

  • ์Œ์‹ ์ฃผ๋ฌธ ์•ฑ์—์„œ ๊ฐ€๊ฒŒ์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›๋Š”๋‹ค. ์ด ๊ณผ์ •์ด API๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง„๋‹ค.
  • ์ธํ„ฐ๋„ท์—์„œ ๊ด‘๊ณ ๋ฅผ ํด๋ฆญํ•˜๊ฑฐ๋‚˜ ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ํŠน์ • ์›น์‚ฌ์ดํŠธ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ๋„ ์›น API์˜ ์ผ์ข…์ด๋‹ค.

3) Swift Codable

Codable์€ Swift์—์„œ JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ์กฐ์ฒด ๋˜๋Š” ํด๋ž˜์Šค์™€ ์‰ฝ๊ฒŒ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ํ”„๋กœํ† ์ฝœ์ด๋‹ค.

์‚ฌ์šฉ๋ฒ• ์˜ˆ์‹œ

struct User: Codable {
    let name: String
    let age: Int
}

// JSON ๋ฐ์ดํ„ฐ๋ฅผ Swift ๊ฐ์ฒด๋กœ ๋””์ฝ”๋”ฉ  
if let jsonData = jsonString.data(using: .utf8) {
    let user = try? JSONDecoder().decode(User.self, from: jsonData)
}

4) URL ๊ตฌ์กฐ

URL(Uniform Resource Locator)์€ ์›น ์ƒ์—์„œ ์ž์›์„ ์ฐพ๊ธฐ ์œ„ํ•œ ์ฃผ์†Œ๋‹ค.

<URL ์˜ˆ์‹œ: https://api.example.com/users?name=John>

- ํ”„๋กœํ† ์ฝœ: https  
- ๋„๋ฉ”์ธ: api.example.com  
- ๊ฒฝ๋กœ: /users  
- ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ: "name=John"

5) REST API

REST API๋Š” HTTP ํ”„๋กœํ† ์ฝœ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ž์›์„ CRUD(Create, Read, Update, Delete) ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜๋‹ค.

<์ฃผ์š” ๋ฉ”์†Œ๋“œ>

- GET: ๋ฐ์ดํ„ฐ ์กฐํšŒ  
- POST: ๋ฐ์ดํ„ฐ ์ƒ์„ฑ  
- PUT: ๋ฐ์ดํ„ฐ ์ˆ˜์ •  
- DELETE: ๋ฐ์ดํ„ฐ ์‚ญ์ œ  

๐Ÿ“Œ 2. URL Session

๊ฐœ๋… ์ •๋ฆฌ

Swift์—์„œ URLSession์€ ๋„คํŠธ์›Œํฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ณ  ๋ฐ›๊ธฐ ์œ„ํ•œ API๋กœ, HTTP ์š”์ฒญ์„ ํ†ตํ•ด ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ง€์›ํ•˜๋ฉฐ, ๋ฐ์ดํ„ฐ ์š”์ฒญ, ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๋ฐ ์—…๋กœ๋“œ์™€ ๊ฐ™์€ ๋‹ค์–‘ํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

1) URLSession์ด๋ž€?

URLSession์€ ๋„คํŠธ์›Œํฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ณ  ๋ฐ›๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค๋‹ค. ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(UX)์„ ๊ฐœ์„ ํ•œ๋‹ค.

2) URLSession Configuration

URLSession์„ ์„ค์ •ํ•  ๋•Œ ๋‹ค์–‘ํ•œ Configuration์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Configuration ํƒ€์ž…

  • default: ๊ธฐ๋ณธ ์„ค์ •์œผ๋กœ ์ผ๋ฐ˜์ ์ธ ๋„คํŠธ์›Œํ‚น์— ์‚ฌ์šฉ
  • ephemeral: ์บ์‹œ์™€ ์ฟ ํ‚ค๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๋Š” ์ž„์‹œ ์„ธ์…˜
  • background: ์•ฑ์ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ๋„ ๋‹ค์šด๋กœ๋“œ ์ž‘์—…์„ ๊ณ„์†ํ•˜๋„๋ก ํ•จ
// Configuration ์‚ฌ์šฉ ์˜ˆ์‹œ
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)

3) URLSession Task

URLSession์€ ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ์ž‘์—…(Task)์„ ์ œ๊ณตํ•œ๋‹ค.

  1. dataTask: ๊ฐ„๋‹จํ•œ ๋ฐ์ดํ„ฐ ์š”์ฒญ์— ์‚ฌ์šฉ
  2. downloadTask: ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์‹œ ์‚ฌ์šฉ
  3. uploadTask: ํŒŒ์ผ ์—…๋กœ๋“œ ์‹œ ์‚ฌ์šฉ
// URLSession ์‚ฌ์šฉ ์˜ˆ์‹œ
let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let data = data {
        // ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
    }
}
task.resume() // ํ•„์ˆ˜ ํ‚ค์›Œ๋“œ

์—ฌ๊ธฐ์„œ resume() ๋ฉ”์†Œ๋“œ๋Š” Task๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๋งŒ๋“œ์‹œ ์‚ฌ์šฉํ•ด ์ฃผ์–ด์•ผ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.

๐Ÿš€ ์™œ URLSessionTask์—์„œ resume()์„ ๋ฐ˜๋“œ์‹œ ํ˜ธ์ถœํ•ด์•ผ ํ• ๊นŒ?

1๏ธโƒฃ resume()์˜ ์—ญํ• 

  • URLSessionTask(์˜ˆ: dataTask, downloadTask, uploadTask)๋Š” ๋น„๋™๊ธฐ ๋„คํŠธ์›Œํ‚น ์ž‘์—…์„ ์œ„ํ•œ ๊ฐ์ฒด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์ƒ์„ฑ๋œ ์งํ›„์—๋Š” ๋ฉˆ์ถ˜ ์ƒํƒœ๋กœ ์ค€๋น„๋งŒ ๋˜์–ด ์žˆ์„ ๋ฟ, ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.

  • resume() ๋ฉ”์†Œ๋“œ๋Š” ๋„คํŠธ์›Œํฌ ์ž‘์—…์„ ์‹œ์ž‘์‹œํ‚ค๋Š” ํŠธ๋ฆฌ๊ฑฐ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ๋งŒ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์„œ๋ฒ„๋กœ ๋ณด๋‚ด์ง€๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ž‘์—…์ด ์‹คํ–‰๋œ๋‹ค.

2๏ธโƒฃ resume()๊ฐ€ ํ•„์š”ํ•œ ์ด์œ 

๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์ค€๋น„ ์ƒํƒœ

  • URLSession์€ ์š”์ฒญ์„ ๋ฐ”๋กœ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ๋Œ€๊ธฐ ์ƒํƒœ๋กœ ๋งŒ๋“ ๋‹ค.
  • resume()์„ ํ˜ธ์ถœํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ž‘์—… ํ์—๋งŒ ๋“ฑ๋ก๋œ ์ƒํƒœ๋กœ, ์•„๋ฌด๋Ÿฐ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค.

๋ช…ํ™•ํ•œ ์ž‘์—… ๊ด€๋ฆฌ

  • ๋„คํŠธ์›Œํฌ ์ž‘์—…์˜ ์‹คํ–‰์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์–ธ์ œ ๋„คํŠธ์›Œํฌ ์ž‘์—…์„ ์‹œ์ž‘ํ• ์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

3๏ธโƒฃ resume() ํ˜ธ์ถœ ์˜ˆ์‹œ

let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
    if let data = data {
        print("Data received: \(data)")
    }
}
// ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ๋ฐ˜๋“œ์‹œ resume() ํ˜ธ์ถœ ํ•„์š”
task.resume()

4๏ธโƒฃ resume()์„ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด?

  • ๋„คํŠธ์›Œํฌ ์š”์ฒญ์ด ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์ด ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๊ณ , ์ฝœ๋ฐฑ ํด๋กœ์ €๋„ ํ˜ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋˜๋Š” ์ž‘์—… ๋ˆ„๋ฝ์˜ ์›์ธ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

5๏ธโƒฃ suspend()์™€์˜ ๊ด€๊ณ„

  • resume() ์™ธ์—๋„, ๋„คํŠธ์›Œํฌ ์ž‘์—…์„ ์ผ์‹œ ์ค‘์ง€ํ•˜๋ ค๋ฉด suspend()๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • resume()๊ณผ suspend()๋ฅผ ๋ฒˆ๊ฐˆ์•„ ํ˜ธ์ถœํ•˜์—ฌ ์ž‘์—…์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.
task.suspend()  // ์ž‘์—… ์ผ์‹œ ์ค‘์ง€
task.resume()   // ์ผ์‹œ ์ค‘์ง€ ํ›„ ์žฌ๊ฐœ

์ฆ‰, resume()์€ URLSessionTask์˜ ์ž‘์—… ์‹คํ–‰์„ ์‹œ์ž‘ํ•˜๋Š” ์ค‘์š”ํ•œ ๋ฉ”์†Œ๋“œ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด ๋„คํŠธ์›Œํฌ ์ž‘์—…์ด ๋Œ€๊ธฐ ์ƒํƒœ๋กœ๋งŒ ๋‚จ์•„, ์š”์ฒญ๊ณผ ์‘๋‹ต ์ฒ˜๋ฆฌ๊ฐ€ ์ „ํ˜€ ์ด๋ฃจ์–ด์ง€์ง€ ์•Š๋Š”๋‹ค.
๋”ฐ๋ผ์„œ URLSession ์ž‘์—…์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐ˜๋“œ์‹œ resume()์„ ํ˜ธ์ถœํ•ด ๋„คํŠธ์›Œํ‚น ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.

4) URLRequest

URLRequest๋Š” HTTP ์š”์ฒญ์„ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. ์š”์ฒญ ๋ฉ”์†Œ๋“œ, ํ—ค๋”, ๋ฐ”๋”” ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • HTTP ๋ฉ”์†Œ๋“œ ์„ค์ •:
var request = URLRequest(url: url)
request.httpMethod = "POST"  // HTTP ๋ฉ”์†Œ๋“œ ์„ค์ •
  • HTTP ํ—ค๋” ์ถ”๊ฐ€:
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
  • URLQueryItem:
    GET ์š”์ฒญ์—์„œ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.
var components = URLComponents(string: "https://api.example.com/search")
components?.queryItems = [
    URLQueryItem(name: "query", value: "Swift"),
    URLQueryItem(name: "page", value: "1")
]

if let url = components?.url {
    print(url)  // https://api.example.com/search?query=Swift&page=1
}

-Today's Lesson Review-

์˜ค๋Š˜์€ JSON ํŒŒ์ผ ํ˜•์‹์˜ ์ธ์ฝ”๋”ฉ, ๋””์ฝ”๋”ฉ์— ๋Œ€ํ•ด ํ•™์Šตํ•˜๊ณ ,
API๋ž€ ๋ฌด์—‡์ธ์ง€, Swift์—์„œ ๋„คํŠธ์›Œํ‚น ํ†ต์‹ ์€ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ๊ณต๋ถ€ํ–ˆ๋‹ค.
์•„์ง์€ ๋ชจ๋‘ ์–ด๋ ต๊ณ  ๋‚ฏ์„  ๊ฐœ๋…๋“ค์ด๋ผ ๋ฐ˜๋ณต์ ์ธ ์—ฐ์Šต๊ณผ ๋งŽ์€ ๊ณต๋ถ€๊ฐ€ ํ•„์š”ํ•  ๊ฒƒ ๊ฐ™๋‹ค.
profile
์ด์œ ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ์“ฐ์ž!!

0๊ฐœ์˜ ๋Œ“๊ธ€