[9주차] 네트워크

Seoyoung Lee·2023년 1월 16일

UMC

목록 보기
8/8
post-thumbnail

Standard Mission

  • ‘공공데이터포털’의 API를 활용해 서버 데이터 가져와보기
    • 반드시 JSON 데이터를 데이터 모델을 걸쳐 디코딩하여 Swift에서 사용할 수 있게 변환해야 합니다!
  • Google, Kakao 등의 소셜 로그인 구현해보기
    • API명세서나 여러 자료를 통해 차근차근 진행해보아요!
    • 한 가지 힌트 :
      소셜 로그인을 구현하기 위해선 해당 기업에서 제공하는 라이브러리(SDK)를 import하셔야 합니다. (CocoaPods에 설치 후 import)

구현 화면

데이터 모델

// TourDataModel.swift
struct TourData: Codable {
    var comMsgHeader: TourComHeader
    var msgHeader: TourMsgHeader
    var msgBody: [TourBody]
}

struct TourComHeader: Codable {
    var successYN: String
    var returnCode: String
    var returnMessage: String
}

struct TourMsgHeader: Codable {
    var pageNo: Int
    var totalCount: Int
    var totalPage: Int
    var numOfRows: Int
}

struct TourBody: Codable {
    var tourSeq: String
    var id: String
    var name: String
    var recommend: String
    var expression: String
    var dCode: String?
    var tGubun: String?
    var pGubun: String?
    var lGubun: String?
    var cGubun: String?
    var sGubun: String?
    var addr1: String
    var addr2: String?
    var zipcode: String?
    var nAddr1: String?
    var nAddr2: String?
    var telCode: String
    var telKuk: String
    var telNo: String
    var hitCnt: String
    var dTag: String?
    var dTel: String?
    var idxImgPath: String?
    var idxImgName: String?
    var dCodeNm: String?
    var contents2: String?
    var imgIdx: String?
    var keyword: String?
    var useYn: String
    var dLang: String
    var cid: String?
}

이 API는 Response로 오는 데이터들이 엄청 많은데, 여기서는 name, recommend(추천 여부), addr1, addr2(기본주소, 상세주소), idxImgPath(썸네일물리적저장경로)만 사용했다.

서버와 통신하기

나는 Alamofire를 사용해서 서버 통신을 구현했다.

extension ViewController {
    func getTourData() {
        let url = "http://apis.data.go.kr/6300000/tourDataService/tourDataListJson?serviceKey=key&pageNo=1&numOfRows=30"
        
        AF.request(url, method: .get)
            .validate()
            .responseDecodable(of: TourData.self) { response in
                switch response.result {
                case .success(let response):
                    self.tourData = response
                    self.tableView.reloadData()
                case .failure(let error):
                    print(error.localizedDescription)
                }
            }
    }
}

원래 request parameter를 따로 변수에 넣고 요청을 보내려고 했는데 디코딩 실패 에러가 떴다. 그래서 url에 파라미터를 통째로 넣었더니 이건 정상적으로 응답이 온다. 왜지…..

이미지 로딩 해결하기

	func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "mainCell") as? MainTableViewCell else {
            return UITableViewCell()
        }
        
        guard let tourBody = tourData?.msgBody else {
            return UITableViewCell()
        }
        
        let data = tourBody[indexPath.row]
        
        cell.titleLabel.text = data.name
        cell.recommendationLabel.isHidden = data.recommend == "Y" ? false : true
        cell.keywordLabel.text = "\(data.addr1) \(data.addr2 ?? "")"
        if let imagePath = data.idxImgPath {
						if let url = URL(string: "http://www.daejeon.go.kr/" + imagePath) {
                cell.tourImageView.load(url: url)
            }
        
        return cell
    }
extension UIImageView {
    func load(url: URL) {
        DispatchQueue.global().async { [weak self] in
            if let data = try? Data(contentsOf: url) {
                if let image = UIImage(data: data) {
                    DispatchQueue.main.async {
                        self?.image = image
                    }
                }
            }
        }
    }
}

처음에는 cellForRowAt 메소드에서 그냥 URL로 이미지를 가져오도록 했다. 그래서 스크롤을 할 때마다 이미지가 다시 로드되는 문제가 있었다.

검색을 해보니 캐시를 사용해서 캐시에 데이터가 없는 경우에만 서버와 통신하도록 하면 해결이 되는 것 같았다.

[iOS - swift] TableView 캐시를 이용한 효율적인 이미지 로딩 방법 (async, cache)

위 블로그 내용은 너무 복잡해서………ㅎㅎ 더 찾아보다 Kingfisher라는 라이브러리를 발견했다.

Kingfisher는 이미지 다운로드뿐만 아니라 캐싱까지 지원해주기 때문에 간단하게 이미지 로딩을 구현할 수 있었다.

	func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
				// ...
        if let imagePath = data.idxImgPath {
						// Kingfisher 라이브러리 사용
            KF.url(URL(string: "http://www.daejeon.go.kr/" + imagePath)).set(to: cell.tourImageView)
        }
        
        return cell
    }

이제 이미지 로드가 한 번만 이뤄진다!

문자열 URL 변환부터 image view 이미지 설정까지 코드 한 줄로 끝내니까 정말 너무 편하다…!!!!

위에 캐시 사용법이랑 Kingfisher에 있는 다른 기능들도 나중에 더 알아봐야겠다.

profile
나의 내일은 파래 🐳

0개의 댓글