안드로이드에서는 Retrofit을 이용해서 꽤 깔끔한 구조의 네트워크 모듈을 만들 수 있는데, swift에서 alamofire로 하려니까 좀 어려운 감이 있다. 찾아보니 Moya라는 것이 있어서 공부해봤는데, 완전히 마음에 드는 건 아니지만 RxAlamofire 보다는 나은 것 같다.
상속용 Repository 클래스를 만든다.
import Foundation import Moya import RxMoya import RxSwift /// 네트워크 호출 상속용 /// https://github.com/Moya/Moya class BaseRepository<API: TargetType> { let disposeBag = DisposeBag() private let provider = MoyaProvider<API>() lazy var rx = provider.rx }
상속용 API 클래스도 만든다. 저 변수들은 일종의 초기값을 지정해두는 거고, 필요하면 자식 클래스에서 다시 선언해서 사용하면 된다.
import Foundation import Moya protocol BaseAPI: TargetType {} extension BaseAPI { var baseURL: URL { URL(string: "https://api.github.com")! } var method: Moya.Method { .get } var sampleData: Data { Data() } var task: Task { .requestPlain } var headers: [String: String]? { nil } }
자동으로 변환받을 모델 클래스도 만든다.
import Foundation struct TestModel: Decodable { var id: Int var name: String var login: String }
실제 Repository 클래스를 만든다.
import Foundation import Moya final class TestRepository: BaseRepository<TestAPI> { static let shared = TestRepository() private override init() {} /// 아이디로 사용자 정보 가져오기 /// - Parameters: /// - name: 로그인 아이디 /// - completion: 완료 후 호출 func user(_ name: String, _ completion: @escaping (TestModel?, Error?) -> Void) { rx.request(.profile(name)) .filterSuccessfulStatusCodes() .map(TestModel.self) // .debug() .subscribe(onSuccess: { completion($0, nil) }, onError: { completion(nil, $0) }) .disposed(by: disposeBag) } } enum TestAPI { case profile(String) } extension TestAPI: BaseAPI { var path: String { switch self { case let .profile(name): return "/users/\(name)" } } }
실제 호출은 이렇게 하면 된다.
TestRepository.shared.user("susemi99") { if let error = $1 { print("error: \(error)") } guard let user = $0 else { return } print("user: \(user)") }