-
Swift Moya 설치 및 내용, RxMoyaSwift 2021. 10. 13. 20:20
URLSession, Alamofire를 사용한뒤, Moya 를 사용해보기로 했다. => 적용하고나서의 나 대만족
우선 알아야되는 사항 13이상부터 가능함.
- Moya' has a minimum deployment target of iOS 13.0
설치방법
pod file에 아래를 추가
pod 'Moya'
pod install 하면, alamofire와 함께 install 되는것을 확인 할 수 있다.
RxSwift를 사용하면서 Moya를 사용한다면 아래처럼 설치해야한다.
pod 'Moya/RxSwift'
설명
Moya 란, Alamofire를 한번 더 감싼 네트워크 라이브러리 할 수 있다. 그렇다면 왜 굳이 이런게 필요할까? 보통 작성하는 APIManager or NetworkModel의 역할을 대신 해줌으로써 네트워크 추상화 계층을 만들어 준다.
어디서 시작하는지, 어떻게 다시 시작하는지 에 대한 내용을 더 쉽게 만들 수 있다는 말.
또 다음과 같은 멋진 기능도 해준다고 설명한다
- Compile-time checking for correct API endpoint accesses.
- Lets you define a clear usage of different endpoints with associated enum values.
- Treats test stubs as first-class citizens so unit testing is super-easy.
enum 타입 기반으로 type-safe한 레이어 구성이 가능하고 endPoint에 target 커스터마이징 자유도가 높아서 좋았다.
특히 service를 만들때 단순히 TargetType을 준수하면서 쉽게 작성가능하다.
아래가 git에서 작성해둔 Moya의 장점을 시각화한것이다.
+ 참고로 사용은 하지 않았지만 RxMoya도 있다.
사용예시
아래처럼 통신을 호출해서 사용한다.
private let mainProvider = MoyaProvider<MainService>() mainProvider.request(.inquiryAllAccouunt(inquiryModel: InquiryRequestModel())) { (result) in // self.showLoading.accept(true) loading 끄는 로직 switch result { case .success(let response): if let model = ModelClassName.decode(data: response.data) { // data processing } case .failure(let error): print("error: \(error)") } }
RxSwift 예시
provider = MoyaProvider<GitHub>() provider.rx.request(.userProfile("ashfurrow")).subscribe { event in switch event { case let .success(response): image = UIImage(data: response.data) case let .error(error): print(error) } }
실제 Service 코드
import Foundation import Moya enum RootService { case doStart(rootModel: RootRequestModel) // 이런식으로 정의 case loggedIn(loginModel: LoginRequestModel) } extension RootService: TargetType { var baseURL: URL { let urlString = "https://~~" guard let url = URL(string: urlString) else { fatalError() } return url } var path: String { switch self { case .doStart(rootModel: _): return "/testDoStart" // 이런식으로 case .loggedIn(loginModel: _): return "" } } var method: Moya.Method { switch self { case .doStart(rootModel: _), .loggedIn(loginModel: _): return .post } } var sampleData: Data { switch self { case .doStart(let test): return "{'name':'\(test)'}".data(using: .utf8)! case .loggedIn(let test): return "{'name':'\(test)'}".data(using: .utf8)! } } var task: Task { switch self { case .doStart(let rootModel): // 나는 이런식으로 작성 구글링 해보면 다른방법도 엄청 많음 return .requestCustomJSONEncodable(rootModel, encoder: JSONEncoder()) case .loggedIn(let loginModel): return .requestCustomJSONEncodable(loginModel, encoder: JSONEncoder()) } } var headers: [String: String]? { return ["Content-Type": "application/json"] } var validationType: ValidationType { return .successCodes // 이걸 사용하면 HTTP Code가 200에서 299인 경우 요청 성공으로 간주해줌 } }
결론
실제로 소스코드가 굉장히 직관적이고 사용하기 편했다. 나는 또 사용할것같다. 실제로 뭔가 request response만 간결히 신경쓸 수 있었다고 생각한다.
특히 코드에서 다른점을 보자면, Alamofire를 사용해도 Network Layer에 접근 할수 없으니(request에 Url 넣어줘야함) 따로 APIManager 이런걸 만드는데 템플릿이 없으니 enum 기반 type safe한 Moya가 재사용에도 유리했다.
++
import Foundation import Moya enum APIEnvironment: String { case dev = "https://~~" case test = "https://~~" } struct NetworkManager { fileprivate let provider = MoyaProvider<RootService>() static let environment: APIEnvironment = .dev } // 이런식으로 NetworkManager 를 만들어두고 실제로는 적용해서 쓰면 된다. // 위의 target쪽에 아래처럼 baseURL 수정 public var baseURL: URL { guard let url = URL(string: NetworkManager.environment.rawValue) else { fatalError("fatal error") } return url }
조금 더 작성하자면 아래처럼 BaseAPI(명명 수정 가능)를 만들어 두고 사용하는것도 좋은 방법이다.
protocol BaseAPI: TargetType {} extension BaseAPI { var baseURL: URL { guard let url = URL(string: MoyaNetworkManager.environment.rawValue) else { fatalError("fatal error") } return url } var path: String { return "" } var method: Moya.Method { .post } var sampleData: Data { Data() } var task: Task { .requestPlain } var headers: [String: String]? { return ["Content-Type": "application/json"] } public var validationType: ValidationType { return .successCodes } } // 내가 사용하는 service에서 enum RootService { case doStart(rootModel: RootRequestModel) } extension RootService: BaseAPI { var sampleData: Data { switch self { case .doStart(let trxCode): return "{'name':'\(trxCode)'}".data(using: .utf8)! } } var task: Task { switch self { case .doStart(let rootModel): return .requestCustomJSONEncodable(rootModel, encoder: JSONEncoder()) } } // 사실 보통 path를 custom함. }
참고
https://ios-development.tistory.com/193 : Rx에 대한 예제는 글에 적지 못했지만, 여기를 많이 참고했다 감사합니다.
728x90'Swift' 카테고리의 다른 글
swift Pecker란 (0) 2021.11.15 Xcode 빌드 속도 높이기2 - cocoapods-binary-cache (1) 2021.11.11 자꾸 까먹는 Swift Array 안전하게 배열 조회 하는법 (0) 2021.09.30 Computed Property + Access Control (0) 2021.09.30 Builder - dynamicMemberLookup (+ KeyPath) (0) 2021.09.30