在Android开发中有很是强大的 Retrofit 请求,结合RxJava能够很是方便实现 RESTful API 网络请求。在 iOS开发中也有很是强大的网络请求库 Moya ,Moya是一个基于 Alamofire 开发的,轻量级的Swift网络层。Moya的可扩展性很是强,能够方便和RXSwift、ObjectMapper结合。html
咱们先用服务端定义几个REST API,开发者根据本身的条件来实现。git
{
"error": "密码错误",
"error_code": "password_error"
}复制代码
// MyApiService.swift
import Moya
enum MyApiService {
case login(username:String,password:String)
case user(userId:String)
case userQuery(keyword:String)
}
extension MyApiService:TargetType{
// 定义请求的host
var baseURL: URL {
return URL(string: "http://127.0.0.1:8080")!
}
// 定义请求的路径
var path: String {
switch self {
case .login(_, _):
return "/account/login"
case .user(let userId):
return "user/\(userId)"
case .userQuery(_):
return "user/query"
}
}
// 定义接口请求方式
var method: Moya.Method {
switch self {
case .login:
return .post
case .user,.userQuery:
return .get
}
}
// 定义模拟数据
var sampleData: Data {
switch self {
case .login(let username, _):
return "{\"username\": \"\(username)\", \"id\": 100}".data(using: String.Encoding.utf8)!
case .user(_):
return "{\"username\": \"Wiki\", \"id\": 100}".data(using: String.Encoding.utf8)!
case .userQuery(_):
return "{\"username\": \"Wiki\", \"id\": 100}".data(using: String.Encoding.utf8)!
}
}
// 构建参数
var task: Task {
switch self {
case .login(let username, let passowrd):
return .requestParameters(parameters: ["username": username,"passowrd": passowrd], encoding: URLEncoding.default)
case .user(_):
return .requestPlain
case .userQuery(let keyword):
return .requestParameters(parameters: ["keyword": keyword], encoding: URLEncoding.default)
}
}
// 构建请求头部
var headers: [String : String]? {
return ["Content-type": "application/json"]
}
}复制代码
let provider = MoyaProvider<MyApiService>()
// Moya 提供最原始的请求方式,响应的数据是二进制
provider.request(.user(userId: "101")){ result in
// do something with the result
let text = String(bytes: result.value!.data, encoding: .utf8)
print("text1 = \(text)")
}
// 结合RxSwift,响应的数据是二进制
provider.rx.request(.user(userId: "101")).subscribe({result in
// do something with the result
switch result {
case let .success(response):
let text = String(bytes: response.data, encoding: .utf8)
print("text2 = \(text)")
case let .error(error):
print(error)
}
})
// 经过mapJSON把数据转换成json格式
provider.rx.request(.user(userId: "101")).mapJSON().subscribe({result in
// do something with the result
switch result {
case let .success(text):
print("text3 = \(text)")
case let .error(error):
print(error)
}
})
// 经过mapJSON把数据转换成json格式,并转换成最多见的Observable
provider.rx.request(.user(userId: "101")).mapJSON().asObservable().subscribe(onNext: { result in
// do something with the result
print("text4 = \(result)")
}, onError:{ error in
// do something with the error
})复制代码
RxBlocking使用教程 ,能够使用同步的方式请求网络github
import RxBlocking
do{
let text = try provider.rx.request(.user(userId: "101")).mapJSON().toBlocking().first()
print("text5 = \(text)")
}catch{
print(error)
}复制代码
pod 'ObjectMapper', '~> 3.4'复制代码
// MoyaRxSwiftObjectMapperExtension.swift
import Foundation
import RxSwift
import Moya
import ObjectMapper
public extension PrimitiveSequence where TraitType == SingleTrait, ElementType == Response {
func mapObject<T: BaseMappable>(type: T.Type) -> Single<T> {
return self.map{ response in
return try response.mapObject(type: type)
}
}
func mapArray<T: BaseMappable>(type: T.Type) -> Single<[T]> {
return self.map{ response in
return try response.mapArray(type: type)
}
}
}
public extension ObservableType where E == Response {
func mapObject<T: BaseMappable>(type: T.Type) -> Observable<T> {
return self.map{ response in
return try response.mapObject(type: type)
}
}
func mapArray<T: BaseMappable>(type: T.Type) -> Observable<[T]> {
return self.map{ response in
return try response.mapArray(type: type)
}
}
}
public extension Response{
func mapObject<T: BaseMappable>(type: T.Type) throws -> T{
let text = String(bytes: self.data, encoding: .utf8)
if self.statusCode < 400 {
return Mapper<T>().map(JSONString: text!)!
}
do{
let serviceError = Mapper<ServiceError>().map(JSONString: text!)
throw serviceError!
}catch{
if error is ServiceError {
throw error
}
let serviceError = ServiceError()
serviceError.message = "服务器开小差,请稍后重试"
serviceError.error_code = "parse_error"
throw serviceError
}
}
func mapArray<T: BaseMappable>(type: T.Type) throws -> [T]{
let text = String(bytes: self.data, encoding: .utf8)
if self.statusCode < 400 {
return Mapper<T>().mapArray(JSONString: text!)!
}
do{
let serviceError = Mapper<ServiceError>().map(JSONString: text!)
throw serviceError!
}catch{
if error is ServiceError {
throw error
}
let serviceError = ServiceError()
serviceError.message = "服务器开小差,请稍后重试"
serviceError.error_code = "parse_error"
throw serviceError
}
}
}
class ServiceError:Error,Mappable{
var message:String = ""
var error_code:String = ""
required init?(map: Map) {}
init() {
}
func mapping(map: Map) {
error_code <- map["error_code"]
message <- map["error"]
}
var localizedDescription: String{
return message
}
}
复制代码
// User.swift
import ObjectMapper
class User: Mappable {
required init?(map: Map) {}
func mapping(map: Map) {
userId <- map["userId"]
name <- map["name"]
age <- map["age"]
}
var userId:Int = 0
var name:String = ""
var age:Int = 0
}复制代码
do{
let user = try provider.rx.request(.user(userId: "101")).mapObject(type: User.self).toBlocking().first()
print("user.name = \(user?.name)")
}catch{
print(error)
}
do{
let user = try provider.rx.request(.user(userId: "101")).asObservable().mapObject(type: User.self).toBlocking().first()
print("user.name = \(user?.name)")
}catch{
print(error)
}
do{
let users = try provider.rx.request(.userQuery(keyword: "Wiki")).mapArray(type: User.self).toBlocking().first()
print("test8 users.count = \(users?.count)")
}catch{
if error is ServiceError {
print((error as! ServiceError).message)
}
print(error)
}复制代码
private func JSONResponseDataFormatter(_ data: Data) -> Data {
do {
let dataAsJSON = try JSONSerialization.jsonObject(with: data)
let prettyData = try JSONSerialization.data(withJSONObject: dataAsJSON, options: .prettyPrinted)
return prettyData
} catch {
return data // fallback to original data if it can't be serialized. } }复制代码
let provider = MoyaProvider<MyApiService>(plugins: [NetworkLoggerPlugin(verbose: true, responseDataFormatter: JSONResponseDataFormatter)])复制代码
原文地址json