๊ธฐํƒ€/iOS๐ŸŽ

[iOS/Swift] ํ…Œ์ด๋ธ”๋ทฐ ์…€์— API ์—ฐ๊ฒฐํ•˜๊ธฐ (GETํ†ต์‹ , Alamofire์ด์šฉ)

yujindonut 2022. 6. 17. 17:53
728x90

์„œ๋ฒ„ ๊ฐœ๋ฐœ์ž๋ถ„์ด ๋งŒ๋“ค์–ด์ฃผ์‹  ํŠธ์œ„ํ„ฐ ํŠธ์œ—๋ฆฌ์ŠคํŠธ API๋ฅผ ์ด์šฉํ•ด tableview ์…€๊ณผ ๋ฐ์ดํ„ฐ๋“ค์„ ์—ฐ๊ฒฐ์‹œ์ผœ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

 

 


Request header์™€ Response Body๋ฅผ ํ™•์ธํ•ด Response๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค!

 

- API ๋ช…์„ธ์„œ ํ™•์ธํ•˜๊ธฐ

Postman์„ ํ†ตํ•ด ํ™•์ธํ•ด๋ณด๋‹ˆ, ํŠธ์œ— ๋ฆฌ์ŠคํŠธ๊ฐ€ JSON ํ˜•ํƒœ๋กœ ์ž˜ ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!


1. API ๋ช…์„ธ์„œ์— ๋งž๊ฒŒ, response๋ฅผ ๋ฐ›์„ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

[Model/Twitt.swift]

import Foundation

struct TwittResponse : Codable {
    let isLike : Bool
    let isRetwit : Bool
    let twitId : String
    let content : String
    let likeCount : Int
    let writer : YJWriter
    
    enum CodingKeys : String, CodingKey {
        case twitId = "_id"
        case content
        case writer
        case likeCount
        case isLike
        case isRetwit
    }
}

 

2. Router ๊ฐ์ฒด์—์„œ ๊ฒฝ๋กœ์™€ HTTP Method ์„ค์ •์„ ํ•ด์ค๋‹ˆ๋‹ค.

 

import Foundation
import Alamofire
import UIKit

enum YJUserRouter {
    case getUser
    case getList
    case postLike(postId : String)
}

extension Router : BaseRouter {
    
    var method: HTTPMethod {
        switch self{
        case .getUser, .getList:
            return .get
        case .postLike:
            return .post
        }
    }
    
    var parameters: RequestParams {
        switch self {
        case .getList, .getUser, .postLike:
            return .requestPlain
        }
    }
    
    var header: HeaderType {
        return .auth
    }
    
    var path : String {
        switch self {
        case .getUser:
            return "/user"
        case .getList:
            return "/twit"
        case .postLike(let postId):
            return "/like/\(postId)"
        }
    }
}

 

3. ServiceํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ค๋‹ˆ๋‹ค.

์„œ๋น„์Šค ํŒŒ์ผ์•ˆ์—์„ , API ๋ช…์„ธ์„œ์— ๋งž๊ฒŒ ๋‚ด์šฉ๋“ค์„ ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„์— request๋ฅผ ๋ณด๋‚ด๊ณ , response๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.

 

import UIKit
import Alamofire

class TwittService : BaseService {
    
    static let shared = TwittService()
    
    private override init() { }
    
    func getList(completion : @escaping (NetworkResult<Any>) -> (Void)) {
        
        AFmanager.request(Router.getList)
            .validate(statusCode: 200...500)
            .responseData { response in
                switch response.result {
                    
                case .success:
                    guard let statusCode = response.response?.statusCode
                    else {return}
                    guard let data = response.data else {return}
                    let networkResult = self.judgeStatus(by: statusCode, data,[TwittResponse].self)
                    completion(networkResult)
                    
                case .failure(let err):
                    print(err.localizedDescription)
                }
            }
    }

}

 

request์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ Router.getList๊ฐ€ ๋“ค์–ด๊ฐ€์žˆ์Šต๋‹ˆ๋‹ค.

Router์•ˆ์—๋Š” url, ํ†ต์‹ ํ•  API์ฃผ์†Œ, HTTP Method, ์š”์ฒญ๋ฐฉ์‹, ์ธ์ฝ”๋”ฉ ๋ฐฉ์‹, ์š”์ฒญ ํ—ค๋”์˜ ์ •๋ณด๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

[BaseService.swift]

    func judgeStatus<T: Codable>(by statusCode: Int, _ data: Data, _ type: T.Type) -> NetworkResult<Any> {
        let decoder = JSONDecoder()
        guard let decodedData = try? decoder.decode(GeneralResponse<T>.self, from: data)
        else { return .pathErr }
        print(decodedData)
        switch statusCode {
        case 200:
            return .success(decodedData.data ?? "None-Data")
        case 201..<300:
            return .success(decodedData.data as Any)
        case 400..<500:
            return .requestErr(decodedData.status)
        case 500:
            return .serverErr
        default:
            return .networkFail
        }
    }

 

networkResult๋Š” ์œ„์— ๋งŒ๋“ค์–ด์ค€ [TwittResponse] ๋ฐฐ์—ด์˜ ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ decodeํ•ด์ค๋‹ˆ๋‹ค.

 

 

๋ฐฐ์—ด์•ˆ์˜ indexPath.row์™€ cell์˜ ๊ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฐ๊ฒฐ์‹œ์ผœ์ค๋‹ˆ๋‹ค.

extension YujinStoryboard2ViewController : UITableViewDataSource{
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if twittDataList[indexPath.row].isRetwit == false {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: TwitterMyTwittTableViewCell.identifier) as? TwitterMyTwittTableViewCell else {return UITableViewCell() }
            cell.setData(twittDataList[indexPath.row])
            cell.postId = twittDataList[indexPath.row].twitId
            return cell
        } else {
            guard let cell = tableView.dequeueReusableCell(withIdentifier: TwitterRetwittTableViewCell.identifier) as? TwitterRetwittTableViewCell else {return UITableViewCell() }
            cell.setData(twittDataList[indexPath.row])
            
            cell.postId = twittDataList[indexPath.row].twitId
            return cell
        }
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return twittDataList.count
    }
}

 

 

4. ViewController ์ž‘์„ฑํ•˜๊ธฐ

[ViewController.swift]

 

( 1 ) ViewController์•ˆ์—  ํŠธ์œ—Response๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” ๋ฐฐ์—ด์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

 

โญ๏ธ ( 2 ) ํ…Œ์ด๋ธ” ๋ทฐ๋Š” ํ™”๋ฉด์ด ๋‹ค์‹œ appearํ• ๋•Œ๋งˆ๋‹ค, ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผํ•ฉ๋‹ˆ๋‹ค! ์ฒ˜์Œ ํ™”๋ฉด์ด ์ƒ์„ฑ๋ ๋•Œ, ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๋ฉด, ํ…Œ์ด๋ธ” ๋ทฐ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ viewWillAppear๋ถ€๋ถ„์— ํŠธ์œ—๋ฆฌ์ŠคํŠธ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์„œ๋น„์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผํ•ฉ๋‹ˆ๋‹ค!

Service๊ฐ์ฒด์—์„œ ๋งŒ๋“ค์–ด๋†“์€ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” response์˜ result์— success๊ฐ€ ๋Œ์•„์˜ค๋ฉด, ๋ฐฐ์—ด๊ฐ์ฒด์— response๋กœ ๋Œ์•„์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘์–ด๋„ฃ์–ด ์ค๋‹ˆ๋‹ค. 

 

( 3 ) ํ…Œ์ด๋ธ” ๋ทฐ์— ์…€์„ ๋“ฑ๋กํ•ด์ค๋‹ˆ๋‹ค~ ํ•ด๋‹น ์…€์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค. 

indexPath.row๋กœ ๋ฐฐ์—ด์˜index๋ฅผ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค!

 

( 4 ) reloadData() ํ˜ธ์ถœ

reloadData()๋Š” ํ…Œ์ด๋ธ”๋ทฐ์˜ ์ธ์Šคํ„ด์Šค ๋ฉ”์„œ๋“œ์ž…๋‹ˆ๋‹ค. ํ…Œ์ด๋ธ”๋ทฐ ์ธ์Šคํ„ด์Šค์—์„œ ์ ‘๊ทผํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

reloadData() ๋ฉ”์„œ๋“œ๋Š” ํ…Œ์ด๋ธ” ๋ทฐ์˜ ํ˜„์žฌ ๋ณด์ด๋Š” ์ „์ฒด ์—ด(row), ์„น์…˜(section) ์—…๋ฐ์ดํŠธ๋ฅผ ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

reloadData() ๋ฉ”์„œ๋“œ๋Š” ํŠน์ • ์—ด, ์„น์…˜์˜ ๋ถ€๋ถ„์  ์—…๋ฐ์ดํŠธ๊ฐ€ ์•„๋‹Œ, ํ…Œ์ด๋ธ” ๋ทฐ์˜ ๋ณด์ด๋Š” ์˜์—ญ ์ „์ฒด๋ฅผ ์—…๋ฐ์ดํŠธ ํ•ด์ค„ ๋•Œ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

    // MARK: - TableView
    // (1)
    var twittDataList : [TwittResponse] = []
    // (2)
	override func viewWillAppear(_ animated: Bool) {
        getTwittList()
    }
    // (3)
    func getTwittList() {
        TwittService.shared.getList {
            result in
            switch result {
            case .success(let data):
                guard let twittList = data as? [TwittResponse] else {return}
                self.twittDataList = twittList
	// (4)
                self.mainTableView.reloadData()
            case .requestErr:
                print("requestErr")
            case .pathErr:
                print("pathErr")
            case .serverErr:
                print("serverErr")
            case .networkFail:
                print("networkFail")
            }
        }
    }

 

728x90