[swift] Alamofire 시작하기 [2]

‍deprecated·2021년 7월 14일
0

데이터 요청하기

강의 자료는 여기에서 다운받습니다.

MainTableViewController.swift 에

import Alamofire

를 작성합니다.

강의자료에는 Alamofire가 설치되어 있어 import만 하면 되지만, 쌩 프로젝트에서 alamofire를 import하기 위해선 해당 프로젝트 폴더에서 터미널을 여신 후,
1. pod init
2. Podfile에 pod 'Alamofire', '~> 5.4' 작성
3. pod install을 하시면 됩니다.

파일 맨 밑에 아래를 작성합니다.

extension MainTableViewController {
  func fetchFilms() {
    // 1
    let request = AF.request("https://swapi.dev/api/films")
    // 2
    request.responseJSON { (data) in
      print(data)
    }
  }
}
  1. Alamofire는 namespacing을 사용하기 때문에, 우리가 사용할 호출 앞에는 AF를 붙입니다.
    request(_:method:parameters:encoding:headers:interceptor:)는 data의 endpoint를 파라미터로 입력받고, 저희는 URL만 보내고 나머지는 default 값으로 사용하겠습니다.
  2. 요청으로부터의 응답을 JSON으로 받겠습니다. JSON 데이터를 한번 출력도 해봅니다.

viewDidLoad()에 아래를 추가합니다.

fetchFilms()

실행하면 이를 통해 Alamofire 요청을 실행하겠죠?

실행해봅시다. 실행하면 아래와 같이 출력됩니다.

success({
  count = 7;
  next = "<null>";
  previous = "<null>";
  results =  ({...})
})

이를 통해 우리는 JSON data를 서버로부터 fetch하는 것을 마쳤습니다!

Codable 데이터 모델 사용하기

위에서 받은 JSON 데이터를 그대로 사용하긴 힘들겠죠. 그래서 데이터를 저장하기 위한 모델을 만들어보겠습니다.

프로젝트에서 Networking 폴더에 새로운 Film.swift 파일을 작성하겠습니다. 그리고 아래와 같이 입력합니다.

struct Film: Decodable {
  let id: Int
  let title: String
  let openingCrawl: String
  let director: String
  let producer: String
  let releaseDate: String
  let starships: [String]
  
  enum CodingKeys: String, CodingKey {
    case id = "episode_id"
    case title
    case openingCrawl = "opening_crawl"
    case director
    case producer
    case releaseDate = "release_date"
    case starships
  }
}

JSON을 데이터모델로 변환하기 위해 Decodable을 struct가 Decodable를 채택한 것을 볼 수 있습니다.

enum CodingKeys를 통해 JSON으로부터 "episode_id"에 해당하는 정보가 들어온다면 이를 Film 구조체에선 id로 받아들이는 모습도 볼 수 있네요.

우리 프로젝트는 디테일한 정보를 간단히 보여주기 위해 Displayble이라는 프로토콜을 정의하고 있습니다. Film.swift 밑에 아래 코드를 추가합니다.

extension Film: Displayable {
  var titleLabelText: String {
    title
  }
  
  var subtitleLabelText: String {
    "Episode \(String(id))"
  }
  
  var item1: (label: String, value: String) {
    ("DIRECTOR", director)
  }
  
  var item2: (label: String, value: String) {
    ("PRODUCER", producer)
  }
  
  var item3: (label: String, value: String) {
    ("RELEASE DATE", releaseDate)
  }
  
  var listTitle: String {
    "STARSHIPS"
  }
  
  var listItems: [String] {
    starships
  }
}

이 extension은 뷰컨트롤러의 자세한 정보가 model의 film에 대한 올바른 label과 값을 가질 수 있도록 합니다.

Networking 폴더에 Films.swift를 추가하고 아래를 작성합니다.

struct Films: Decodable {
  let count: Int
  let all: [Film]
  
  enum CodingKeys: String, CodingKey {
    case count
    case all = "results"
  }
}

이 구조체는 films의 collection을 나타냅니다. 앞 결과창에서 봤듯이 swapi.dev/api/films endpoint는 count, next, previous, results를 반환합니다. 하지만 우리는 count와 results만 필요하므로 이에 해당하는 변수만 적어줍시다.

coding keys를 통해 서버의 results라는 정보가 all로 변환된 것을 볼 수 있습니다.

또한, 데이터모델이 Decodable을 채택함으로써, Alamofire는 JSON 데이터를 우리가 작성한 데이터모델로 변환할 수 있게 됩니다.

MainTableViewController.swift의 fetchFilms()안의 내용을

request.responseJSON { (data) in
  print(data)
}

에서

request.responseDecodable(of: Films.self) { (response) in
  guard let films = response.value else { return }
  print(films.all[0].title)
}

로 교체합니다.
이를 통해, response를 JSON이 아니라, 우리가 작성한 데이터 모델로 바꿀 수 있게 되었습니다. 실행해보면
A new Hope가 출력됩니다. 이는 첫번째 film의 title입니다.

Method Chaining

Alamofire는 Method Chaining을 사용합니다. 이는 한 메소드의 응답을 다른 메소드의 입력으로 연결하는 것입니다. 이를 통해 코드도 컴팩트하고 보기 쉽게 작성할 수 있습니다.

fetchFilms()의 모든 코드를 아래로 교체합니다.

AF.request("https://swapi.dev/api/films")
  .validate()
  .responseDecodable(of: Films.self) { (response) in
    guard let films = response.value else { return }
    print(films.all[0].title)
  }

이를 통해 endpoint를 request하고, 응답이 200~299 범위의 HTML status code를 반환하는 것을 보증함으로써 response를 validate하고, response를 우리가 작성한 데이터 모델로 decode했습니다.

테이블뷰 세팅

MainTableViewController의 맨 위에

var items: [Displayable] = []

를 작성합니다. 우리는 정보의 배열을 저장하기 위해 이 property를 사용할 것입니다.
fetchFilms()의

print(films.all[0].title)

self.items = films.all
self.tableView.reloadData()

로 교체합니다. 이는 가져온 모든 films를 items에 할당하고, 테이블뷰를 reload합니다.

테이블뷰에 내용을 보여주기 위해서 tableView(_:numberOfRowsInSection:) 의 return 값을

return items.count

로 교체하고,
tableView(_:cellForRowAt:)의 cell 선언 바로 밑에

let item = items[indexPath.row]
cell.textLabel?.text = item.titleLabelText
cell.detailTextLabel?.text = item.subtitleLabelText

를 작성합니다.

이를 통해 Displayable를 통해 제공된 property들을 사용하여 cell을 film name과 episode ID로 채워넣었습니다.

실행해봅시다!

Alamofire를 통해 손쉽게 데이터를 외부서버로부터 가져와 ViewController에 표시할 수 있었습니다.

Detail View Controller 설정을 비롯한 보다 자세한 내용은 https://www.raywenderlich.com/6587213-alamofire-5-tutorial-for-ios-getting-started#toc-anchor-009 에서 뒤이어 보실 수 있습니다!

profile
deprecated

0개의 댓글