Swift

RxSwift + Alamofire

반다이크 2022. 7. 14. 11:22
반응형

버스 위치 정보 어플을 만들면서 RxSwift를 사용해서 API 호출을 하는 코드 예시입니다.
reponseDecodable을 통해서 바로 데이터를 변환해서 적용했습니다.

static func getRequest(url: String, param: [String: Any]) -> Observable<Result<BusRouteModel, Error>> {
        
        let header: HTTPHeaders = [
            "Content-Type": "application/json"
        ]
        
        return Observable.create { observer -> Disposable in
            
            AF.request(url, method: .get, parameters: param, encoding: URLEncoding.default, headers: header)
                .responseDecodable(of: BusRouteModel.self) { response in
                    switch response.result {
                    case .success(let data):
                        observer.onNext(.success(data))
                    case .failure(let error):
                        observer.onError(error)
                        
                    }
                }
                return Disposables.create()
        }
}

BusRouteModel

struct BusRouteModel: Codable {
    let comMsgHeader: COMMsgHeader
    let msgHeader: MsgHeader
    let msgBody: MsgBody
}

// MARK: - COMMsgHeader
struct COMMsgHeader: Codable {
    let responseMsgID, responseTime, requestMsgID, successYN: JSONNull?
    let returnCode, errMsg: JSONNull?
}

// MARK: - MsgBody
struct MsgBody: Codable {
    let itemList: [ItemList]
}

// MARK: - ItemList
struct ItemList: Codable {
    let busRouteID, busRouteNm, busRouteAbrv, length: String
    let routeType, stStationNm, edStationNm, term: String
    let lastBusYn, lastBusTm, firstBusTm, lastLowTm: String
    let firstLowTm, corpNm: String

    enum CodingKeys: String, CodingKey {
        case busRouteID = "busRouteId"
        case busRouteNm, busRouteAbrv, length, routeType, stStationNm, edStationNm, term, lastBusYn, lastBusTm, firstBusTm, lastLowTm, firstLowTm, corpNm
    }
}

// MARK: - MsgHeader
struct MsgHeader: Codable {
    let headerMsg, headerCD: String
    let itemCount: Int

    enum CodingKeys: String, CodingKey {
        case headerMsg
        case headerCD = "headerCd"
        case itemCount
    }
}

// MARK: - Encode/decode helpers

class JSONNull: Codable, Hashable {

    public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
        return true
    }

    public var hashValue: Int {
        return 0
    }

    public init() {}

    public required init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if !container.decodeNil() {
            throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
        }
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encodeNil()
    }
}

 

 

Observable: subscribe 전까지 아무일도 일어나지 않음
     -> 구독 후 이벤트가 발생하고 complete 또는 error 이벤트가 발생하기 전까지 next 이벤트가 발생함

create: observer들에게 어떤 event가 발생하는지 알려줌

     -> 

 

disposable: 각종 Disposable을 반환하는 create 메소드를 가진 구조체

     -> 리소스를 해제하고 이벤트 구독을 중지함

 

Observable.create: 인자로 escaping closure를 받음

 

Disposables.create 클로저를 하나 전달하면AnonymousDisposable 인스턴스가 만들어진다. 이 인스턴스의 dispose는 생성될 때 등록해둔 클로저를 실행한다.

 

 

 

 

제네릭 타입을 사용한 예시

 

import Foundation
import RxSwift
import RxCocoa
import Alamofire

class NetworkManager {
    
    static let shared = NetworkManager()

    func getCommonHeaders() -> HTTPHeaders {
        let headers: HTTPHeaders = [
            "Content-Type":"application/json",
        ]
        return headers
    }
    
    func getRequest<T:Decodable>(url: String,
                                 param: [String: Any]?,
                                 responseModel: T.Type) -> Observable<Result<T, Error>> {
            
        let header: HTTPHeaders = [
            "Content-Type": "application/json"
        ]
        
        return Observable.create { observer -> Disposable in
            AF.request(url, method: .get, parameters: param, encoding: JSONEncoding.default, headers: header)
                .responseDecodable(of: responseModel.self) { response in
                    switch response.result {
                    case .success(let data):
                        observer.onNext(.success(data))
                    case .failure(let error):
                        observer.onError(error)
                        
                    }
                }
                return Disposables.create()
        }
    }

}
반응형

'Swift' 카테고리의 다른 글

웹뷰 전체 내역 캡쳐 및 앨범 저장  (0) 2023.01.17
Alamofire Swift  (0) 2022.07.15
iOS ScrollView 설정  (0) 2022.06.05
iOS RxSwift GPS  (0) 2022.05.12
iOS 분리된 타겟 내부 XML 파일 파싱  (0) 2022.05.02