본문 바로가기

Swift 공부

Moya / RxMoya 사용해보기

Swift에서 Alamofire을 사용하다보면 직접 Router 만들거나 NetwokrManager 같은 클래스를 만들어서 사용합니다 그럴경우

 

네트워크 계층이

 

 

                   왼쪽 Network Layer = Router or NetwokrManager                                                                   Moya를 사용 했을경우 통신 계층 구조                      

일반적으로 Moya를 사용하지 않을경우 통신계층 구조가 심플하지 못한 구조를 가질수 있습니다.

 

그런 부분들을 해소 해주는 것이 Moya라이브러리 입니다.

 

Moya의 주요 목표는

Moya는 일반적으로 enum을 사용하여 네트워크 요청을 타입 안전한 방식으로 캡슐화하는데 초점을 맞춤 네트워킹 라이브러리로 네트워크 계층에서 작업할때 추가된 검색 가능성과 함께 컴파일 시간 보장등을 제공 합니다. 

 

 

  • Provider: Moya의 MoyaProvider는 모든 네트워크 서비스와 상호작용할때 만들고 사용할 주요한 객체입니다. 초기화할때 Moya Target을 가지는 일반적인 객체입니다.
  • Target: Moya target은 일반적으로 전체 API 서비스를 설명합니다. 이 경우에는, Marvel target과 Imgur target이 있습니다. 그들 각 타겟은 서비스, 그 자체의 가능한 끝점, 요청을 이행하는 각 끝점에 요구되는 정보를 설명합니다. TargetType 프로토콜을 체택하는 것으로 target을 정의합니다.
  • Endpoint: Moya는 네트워크 요청을 이행하는 요구된 정보의 기본조각을 설명하는 반 내부(semi-internal) 끝점(Endpoint) 객체를 사용합니다(예를들어 HTTP method, request body, header 등) MoyaProvider는 모든 target들을 끝점(Endpoint)으로 변형(transforms)하고, 결국에는 원시 URLRequest로 변형되어 집니다. Endpoints는 높은 수준의 사용자화가 가능하지만, 사용자 정의 맵핑이 필요하지 않으므로 이 튜토리얼의 범위를 벗어납니다.

 

 

//Moya에서 제공하는 BaseRepository 
class BaseRepository<API: TargetType> {
    let disposeBag = DisposeBag()
    private let provider = MoyaProvider<API>()
    lazy var rx = provider.rx
}

 

 

통신을 할 기본 베이스를 제작

토이 프로젝트에서 RxSwift를 사용했기때문에 RxSwift에 맞춰 제작

 

//Moya 라이브러리의 타겟타입을 기본적으로 종속한 BaseAPI
protocol BaseAPI: TargetType {
    
}
//기본값을 세팅
extension BaseAPI {
    var baseURL: URL {
        //서버의 URL을 리턴해주는 싱글톤 패턴
        let serverURL = ServerManager.shared.returnServerURL()
        //기보 URL 세팅
        return URL(string: serverURL)!
    }
    
    var path: String {
        
        return "/indexTest1.php"
    }
    
    // method 이 없을경우 기본적으로
    var method: Moya.Method { .get }
    var sampleData: Data { Data() }
    var task: Task { .requestPlain }
    var headers: [String: String]? { nil }
}

 

 

//딕셔너리타입을 쓰기 쉽게 typealias 선언
typealias DictionaryType = [String: Any]

 

 

 

///통신 객체 
final class NetworkMoya: BaseRepository<MoyaRouter> {
    
    ///싱글톤 제작
    static let shared = NetworkMoya()
    
    /// 아이디로 사용자 정보 가져오기
    /// - Parameters:
    ///   - parameters: 통신에 필요한 파라미터
    /// 테스트서버에서 파라미터에 빈값이 들어올경우
    /// 에러값을 리턴하기때문에 파라미터에 빈값을 넣었을때 빈 제이슨을 넣어줌
    func getRecentUpdateCenter(_ parameters : DictionaryType = ["":""] ,   _ completion: @escaping (resModel?, Error?) -> Void) {
        rx.request(.getRecentUpdateCenterModel(parameters))
        /// StatusCodes 가 성공인지를 걸러내는 값
            .filterSuccessfulStatusCodes()
            //리턴값의 struct형태를 지정
            .map(resModel.self)
            //      .debug()
            //리턴값
            .subscribe(onSuccess: { completion($0, nil) }, onError: { completion(nil, $0) })
            .disposed(by: disposeBag)
    }
    
    
}

 

통신의 종류별 라우터를 선정한다.

enum MoyaRouter  {
    
    ///클라이메이트 서비스에서 최근 업데이트 모델을 요청
    case getRecentUpdateCenterModel(DictionaryType)

}

extension MoyaRouter: BaseAPI {
// 파라미터값을 제작
    public var task: Task {
        switch self {
        case .getRecentUpdateCenterModel(let getParameter):
            var params: [String: Any] = [:]
            var reqBody : [String: Any] = [:]
            params["reqCode"] = "102"
            
            for param in getParameter {
                reqBody[param.key] = param.value
            }
            params["reqBody"] = reqBody
            let paramsJson = try? JSONSerialization.data(withJSONObject:params)
            return .requestData(paramsJson ?? Data())
        }
    }
    
    public var method: Moya.Method {
// 파라미터값을 통신요청 타입을 제작
        switch self {
        case .getRecentUpdateCenterModel(_):
            return .post
        }
    }
}

 

 

이렇게 Moya에서 제공한 라우터를 이용하여 통신객체를 캡슐화를 만들 수 있습니다.

굳이 Moya를 사용하지 않더라도 에러처리가 잘되어있는 통신객체를 직접 만들 수 있지만

상대적으로 시간이 부족하거나 이미 다른사람들이 완성시킨 라우터를 이용하여 통신을 진행하면

절약한 시간을 다른곳에 더 투자할수 있기때문에 Moya 라이브러리 사용을 검토해 보았습니다.

 

 

 

참고자료 https://devmjun.github.io/archive/Moya-Tutorial

 

Swift, Moya가 무엇인지, 어떻게 사용하는지 알아봅니다

 

devmjun.github.io

 

 

이 허접한글을 그래도 읽어주시는 분들이 있어서 업데이트 해봅니다.

 

우선 파라미터를 좀 더 편하게 넣을수 있는 방법입니다.

 

해당 extension을 이용하여 Encodable에서  toDictionary를 만들어주고

 

파라미터를 Struct로 만들어서 관리해줍니다.

extension Encodable {
    var toDictionary : [String: Any] {
        guard let object = try? JSONEncoder().encode(self) else { return [:] }
        guard let dictionary = try? JSONSerialization.jsonObject(with: object, options: []) as? [String:Any] else { return [:] }
        return dictionary
    }
}

 

ex

파라미터를 struct로 만들어

struct getBannerResponse : Codable {

	var param : String
}

 

이런식으로 만들어주고 task를 

 case getBanner(let param) :
            return .requestParameters(parameters: param.toDictionary , encoding: URLEncoding.queryString)

사용해주면 좀 더 편하게 사용 할 수 있습니다.

 

 

'Swift 공부' 카테고리의 다른 글

Swift MVVM  (0) 2022.03.09
Protocol Oriented Programming(POP) - With RxSwift Mvvm  (0) 2022.02.18
WKWebView MemoryLeak 해결  (0) 2021.11.12
타입캐스팅 is , as 와 Any , AnyObject  (0) 2021.08.05
Swift 함수형 프로그래밍  (1) 2021.08.05