๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ก work work work/swift

swift ์‹ค์Šต - 6.1: Movie App ๋งŒ๋“ค๊ธฐ

by hanwitjus 2022. 2. 23.

 

 

 

์˜ค๋Š˜์€ ์ด๋Ÿฐ ์˜ํ™” ์ •๋ณด ์ถœ๋ ฅ ์•ฑ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋ฐฐ์› ๋‹ค.

 

์ด์ „์— ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ์„ ๋งŒ๋“ค ๋•Œ๋‚˜ ์›น์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๋•Œ๋„ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋˜

http request๋ฅผ ๋ณด๋‚ด์„œ response๋ฅผ ๋ฐ›์•„์™€ parsingํ•˜์—ฌ

์›ํ•˜๋Š” ์ •๋ณด๋งŒ์„ ๋นผ๋‚ด์™€์„œ Model์— ์ €์žฅํ•˜๊ณ , ํ™”๋ฉด์— ๋ฟŒ๋ ค์ฃผ๋Š” ๋กœ์ง์ด๋‹ค.

 

์• ํ”Œ์€ ๋ญ”๊ฐ€ ์ด๋Ÿฐ ๊ณต๊ณต api๋ฅผ ์ด์šฉํ•˜๋Š”๊ฒŒ ๋” ์‰ฌ์›Œ๋ณด์˜€๋‹ค.

 

์˜ค๋Š˜ ํ•œ ๋ถ€๋ถ„์„ ์ˆœ์„œ๋Œ€๋กœ ์ •๋ฆฌํ•˜์ž๋ฉด

1. ํ™”๋ฉด ๊ตฌ์„ฑํ•˜๊ธฐ(ํ…Œ์ด๋ธ”๋ทฐ, ๋ทฐ ์…€)

2. ๋ชจ๋ธ ๋งŒ๋“ค๊ธฐ

3. ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ ๋ฐ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

4. ํ™”๋ฉด์— ๋ฟŒ๋ ค์ฃผ๊ธฐ

 

 

 

 

 

 

1. ํ™”๋ฉด ๊ตฌ์„ฑํ•˜๊ธฐ

 

 

 

๋ ˆ์ด์•„์›ƒ์€ ์ด๋ ‡๊ฒŒ ์ƒ๊ฒผ๋‹ค.

 

๋จผ์ € ํ…Œ์ด๋ธ” ๋ทฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ทธ ์•ˆ์— ํ…Œ์ด๋ธ” ๋ทฐ ์…€์„ ๋งŒ๋“ ๋‹ค.

 

ํ…Œ์ด๋ธ” ๋ทฐ ์…€์€

๋ ˆ์ด๋ธ” 4๊ฐœ์™€ ์ด๋ฏธ์ง€ ๋ทฐ 1๊ฐœ๋กœ ๊ตฌ์„ฑ๋˜์–ด์žˆ๋‹ค.

 

์ด ๊ณผ์ •์—์„œ ์˜คํ† ๋ ˆ์ด์•„์›ƒ ์„ค์ •์ค‘์—

Content Hugging Priority๋ฅผ ๋งŒ์ง€๋Š” ๋ถ€๋ถ„์ด ์žˆ์—ˆ๋Š”๋ฐ

๊ฑฐ๊ธฐ์„œ ๋ญ˜ ์ž˜๋ชปํ•œ๊ฑด์ง€ ์•„๋‹Œ์ง€ 

ํƒ€์ดํ‹€์ด ์•„๋ž˜์œ„๊ฐ€ ์ข€ ์งค๋ ค์„œ ๋‚˜์˜ค๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ ์ด๊ฑด ์ฐจ์ฐจ ๊ณ ์ณ์•ผ๊ฒ ๋‹ค.

 

 

 

 

 

 

 

2. ๋ชจ๋ธ ๋งŒ๋“ค๊ธฐ

api๋กœ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋“ค์—์„œ ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ๋นผ์™€์„œ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋ธ์„ ๋งŒ๋“ ๋‹ค.

 

์—ฌ๊ธฐ์„œ JSON ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜๋˜๋Š” response ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ์ •๋ณด๊ฐ€ ์–ด๋–ค ์ด๋ฆ„์œผ๋กœ ๋˜์–ด์žˆ๋Š”์ง€๋ฅผ ๋ณด๊ณ 

๊ทธ ์ด๋ฆ„์ด๋ž‘ ๋˜‘๊ฐ™์ด ํ•˜๋ฉด๋œ๋‹ค. ๊ทธ๋Ÿผ ๋ณ„๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

 

import Foundation

struct MovieModel: Codable {
    let resultCount: Int
    let results: [Result]
}

struct Result: Codable {
    let trackName: String?
    let previewUrl: String?
    let thumbnail: String?
    let shortDescription: String?
    let longDescription: String?
    let currency: String?
    let trackPrice: Double?
    
    enum CodingKeys: String, CodingKey {
        case thumbnail = "artworkUrl100"
        case trackName
        case previewUrl
        case shortDescription
        case longDescription
        case currency
        case trackPrice
    }
}

 

๊ทธ๋ž˜์„œ ์ด๋Ÿฐ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋ฉด ๋œ๋‹ค.

์—ฌ๊ธฐ์„œ ๋งŒ์•ฝ JSONํŒŒ์ผ์— ์žˆ๋Š” ์ด๋ฆ„์œผ๋กœ ์•ˆํ•˜๊ณ  ์ž„์˜๋กœ ์ง€์ •ํ•˜๊ฒ ๋‹ค ํ•˜๋ฉด

๋ฐ‘์— CodingKeys๋ผ๋Š” enum์„ ์„ ์–ธํ•ด์ค˜์•ผ ํ•œ๋‹ค.

์ด๋ฆ„์„ ๋ฐ”๊ฟ”์„œ ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹ค๋ฅธ ๊ฒƒ๋“ค๋„ ๋‹ค ์ ์–ด์ค˜์•ผ ์˜ค๋ฅ˜๊ฐ€ ์•ˆ๋‚œ๋‹ค.

 

 

3. ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ ๋ฐ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ

๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด๋‹ค.

 

๋จผ์ € requestMovieAPI๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค์—ˆ๋‹ค.

 func requestMovieAPI(){
      let sessionConfig = URLSessionConfiguration.default
      let session = URLSession(configuration: sessionConfig)
       
      var components = URLComponents(string: "https://itunes.apple.com/search")
        
      let term = URLQueryItem(name: "term", value: "marvel")
      let media = URLQueryItem(name: "media", value: "movie")
        
      components?.queryItems = [term, media]
        
      guard let url = components?.url else{
          return
     }

 

์„ธ์…˜์„ ๋งŒ๋“ค๋•Œ ์‚ฌ์šฉํ•  sessionConfig๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์„ธ์…˜์„  ๊ทธ configuration์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  URLComponents๋กœ url๋ฅผ ์„ค์ •ํ•ด์ฃผ๋Š”๋ฐ,

๊ทธ ๋’ค์— GET์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋‚ผ ๋•Œ ํ•„์š”ํ•œ ๊ฐ’๋“ค์„ ์„ค์ •ํ•ด์ฃผ๊ณ ,

components?.queryItems = [term, media] ๋กœ url ์ปดํฌ๋„ŒํŠธ ์„ค์ •์„ ํ•ด์ค€๋‹ค์Œ, url์„ ์ƒ์„ฑํ•œ๋‹ค.

 

Apple์˜ API์‚ฌ์šฉ์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

http://resources.organicfruitapps.com/documentation/itunes-store-web-service-search-api/

 

 

  var request = URLRequest(url: url)
  request.httpMethod = "GET"

 

๊ทธ๋ฆฌ๊ณ  ์ƒ์„ฑํ•œ url์„ ์‚ฌ์šฉํ•˜์—ฌ request๋ฅผ ์ƒ์„ฑํ•˜๊ณ  GET๋ฐฉ์‹์œผ๋กœ ์„ค์ •ํ•˜์—ฌ request๋ฅผ ๋ณด๋‚ธ๋‹ค.

 

 

 let task = session.dataTask(with: request) { data, response, error in
       print((response as! HTTPURLResponse).statusCode)
            
       if let hasData = data {
                
           do {
               self.movieModel = try JSONDecoder().decode(MovieModel.self, from: hasData)
                  
               print(self.movieModel ?? "no data")
                    
               DispatchQueue.main.async {
                   self.movieTableView.reloadData()
               }
           }catch{
               print(error)
             }
        }           
    }

๊ทธ๋ฆฌ๊ณ  session.dataTask๋ฅผ request๋ฅผ ํ†ตํ•ด ์‹คํ–‰ํ•˜๋ฉด

data, response, error ์ด๋ ‡๊ฒŒ ์„ธ๊ฐ€์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ฒŒ ๋œ๋‹ค.

 

๊ทธ๊ฑธ ์ด์šฉํ•ด์„œ HttpStatus code๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ ์ฝ˜์†”์— ์ถœ๋ ฅํ•ด๋ณด๊ณ ,

data๋ฅผ JSONDecoder๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŒŒ์‹ฑํ•œ๋‹ค์Œ movieModel์— ์ €์žฅํ•œ๋‹ค.

 

์ด ๋ชจ๋“  ๊ณผ์ •์€ main thread๊ฐ€ ์•„๋‹Œ ๊ณณ์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ

movieTable์„ ๋‹ค์‹œ reloadํ•˜๋Š” ๊ณผ์ •์€ main์—์„œ ์‹คํ–‰๋˜๋„๋ก DispatchQueue ํ•ด์ค€๋‹ค.

 

    task.resume()
    session.finishTasksAndInvalidate()

task๋ฅผ resume์œผ๋กœ ์‹คํ–‰ํ•˜๊ณ , session์„ ๋‹ซ๋Š”๋‹ค.

 

 

4. ํ™”๋ฉด์— ๋ฟŒ๋ ค์ฃผ๊ธฐ

ํ™”๋ฉด์— ๋ฟŒ๋ฆฌ๋Š” ๊ฒƒ์€ ์•ž์—์„œ ์—ฌ๋Ÿฌ๋ฒˆ ํ–ˆ๋˜ ๊ฒƒ๊ณผ ๊ฐ™์ด table view์— delegate, datasource ํ•จ์ˆ˜๋“ค์„ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด์„œ

ํ•  ์ˆ˜ ์žˆ๋‹ค.

extension ViewController: UITableViewDelegate, UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.movieModel?.results.count ?? 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath) as! MovieCell
        
        cell.titleLabel.text = self.movieModel?.results[indexPath.row].trackName ?? ""
        
        cell.descriptionLabel.text =
        self.movieModel?.results[indexPath.row].shortDescription ?? ""
        
        let currency = self.movieModel?.results[indexPath.row].currency ?? ""
        
        let price = self.movieModel?.results[indexPath.row].trackPrice?.description ?? ""
        
        cell.priceLabel.text = currency + " " + price
        return cell
	}
}

๋ฌธ์ œ๋Š” ๊ฐ’์ด ์—†์„ ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๋ถ€๋ถ„์˜ ๋ณ€์ˆ˜๋“ค์ด ์˜ต์…”๋„์ด๋ผ ๊ทธ๊ฑฐ ์ฒ˜๋ฆฌ๋ฅผ ์ž˜ ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

 

์ด์ œ ๋‹ค์Œ์—๋Š” ์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ , ๊ฒ€์ƒ‰์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ’๋“ค์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ํ•  ์˜ˆ์ •์ด๋‹ค.

 

 

LIST

๋Œ“๊ธ€