分享一个自用的带Rac扩展的Moya网络请求工具类

2017-06-05  本文已影响86人  flyrr

一.首先定义一个总的遵守TargetType的协议---方便扩展,在这里可以设置默认的请求方式,方便在写具体的借口枚举时,直接设置path,parameters,省去了还得设置其它必须协议

extension APIable {
    var baseURL: URL {
        return URL(string: RequestManager<RequestOutData>.baseUrl)!
    }
    var method: Moya.Method { return .post }
    var task: Task { return .request }
    var parameterEncoding: ParameterEncoding { return URLEncoding.default }
    var sampleData: Data {
        return "".data(using: String.Encoding.utf8)!
    }
}

2.按接口使用类型分别定义遵守APIable协议的枚举,比如说

和账号有关的
enum AccountAPI {
    //MARK: -登录-
    case login(type: LoginPlatform)
}
extension AccountAPI: APIable {
    var path: String {
        switch self {
        case .login(type: let type):
            switch type {
            case .mobile(account: _, code: _):
                return "user/login.do"
            case .third(type: let third, openid: _, img: _, nick: _, ifbount: _):
                switch third {
                case .qq:       return "user/qqlogin.do"
                case .weixin:   return "user/wxlogin.do"
                case .weibo:    return "user/wblogin.do"
                }
            }
        }
    }
   
    var parameters: [String : Any]? {
        switch self {
        case .login(type: let type):
            switch type {
            case .mobile(account: let account, code: let code):
                return ["account": account, "code": code]
            case .third(type: _, openid: let openid, img: let img, nick: let nick, ifbount: let ifbount):
                let isOld = ifbount ? 1 : 0
                return ["openid": openid, "img": img, "nick": nick, "ifbount": "\(isOld)"]
            }
}
}

具体服务相关等等。。。。省略
/// 业务逻辑相关api
enum ServiceAPI {
    // MARK: - 搜索
    case search(nickname: String)
}

这样写的好处有:
1.不必所有借口都写在一个文件里面,不易查找与修改
2.方便多人开发时,两人都修改同一处代码,提交报错问题。。。

二:设置请求时的请求头,请求超时等等

extension APIable {
    static func endpointClosure<T: APIable>() -> (T) -> Endpoint<T> {
        let endpointClosure = { (target: T) -> Endpoint<T> in
            let endpoint = Endpoint<T>(
                url: target.baseURL.appendingPathComponent(target.path).absoluteString,
                sampleResponseClosure: { .networkResponse(200, target.sampleData) },
                method: target.method,
                parameters: target.parameters,
                parameterEncoding: target.parameterEncoding)
            if let account = target as? AccountAPI {
                switch account {
                case .login(type: _), .getCode(mobile: _, mode: _):
                    return endpoint
                default:
                    return endpoint.adding(
                        httpHeaderFields: ["userid": "\(PreferenceManager.shared[.userid])",
                            "appsign": PreferenceManager.shared[.appsign] ?? ""
                        ])
                }
            } else {
                return endpoint.adding(
                    httpHeaderFields: ["userid": "\(PreferenceManager.shared[.userid])",
                        "appsign": PreferenceManager.shared[.appsign] ?? ""
                    ])
            }
        }
        return endpointClosure
    }
    
    static func requestClosure<T: APIable>() -> (Endpoint<T>, @escaping (Result<URLRequest, MoyaError>) -> Void) -> Void {
    
        let requestC = { (endpoint: Endpoint<T>, done: @escaping ((Result<URLRequest, MoyaError>) -> Void)) in
            if let urlRequest = endpoint.urlRequest {
                var request = urlRequest
                request.timeoutInterval = 10
                done(.success(request))
            } else {
                done(.failure(MoyaError.requestMapping(endpoint.url)))
            }
        }
        
        return requestC
    }
}

三:写个网络请求的提供工具--在这里使用第二步的网络请求有关的设置

private struct ProviderManager {
    static let shared = ProviderManager()
    let apiProvider = ReactiveSwiftMoyaProvider<AccountAPI>(
        endpointClosure: AccountAPI.endpointClosure(),
        requestClosure: AccountAPI.requestClosure(),
        plugins: [NetworkActivityPlugin { UIApplication.shared.isNetworkActivityIndicatorVisible = $0 == .began },
                  NetworkLoggerPlugin(verbose: true)]
    )
    
    let serviceProvider = ReactiveSwiftMoyaProvider<ServiceAPI>(
        endpointClosure: ServiceAPI.endpointClosure(),
        requestClosure: ServiceAPI.requestClosure(),
        plugins: [NetworkActivityPlugin { UIApplication.shared.isNetworkActivityIndicatorVisible = $0 == .began },
                  NetworkLoggerPlugin(verbose: true)]
    )
    private init() {}
}

四:真正网络请求的工具类:

struct RequestManager<Base> where Base: Mappable {
    private init() {}
    static var baseUrl: String { return BaseUrl.net.rawValue }
    //MARK: -返回单个model-
    static func requesObject(_ api: APIable) -> SignalProducer<Base, NetError> {
        let status = RealReachability.sharedInstance().currentReachabilityStatus()
        switch status {
        case .RealStatusNotReachable, .RealStatusUnknown:
          return SignalProducer<Base, NetError>(error: .content)
        case .RealStatusViaWiFi, .RealStatusViaWWAN:
            if let account = api as? AccountAPI {
                let producer: SignalProducer<Base, NetError> =
                    ProviderManager.shared.apiProvider
                        .request(account)
                        .toObject()
                return producer
            }
            else if let service = api as? ServiceAPI {
                let producer: SignalProducer<Base, NetError> =
                    ProviderManager.shared.serviceProvider
                        .request(service)
                        .toObject()
                return producer
            }
            else {
                fatalError()
            }
        }
    }
    //MARK: -返回数组model-
    static func requestArray(_ api: TargetType) -> SignalProducer<[Base], NetError> {
        let status = RealReachability.sharedInstance().currentReachabilityStatus()
        switch status {
        case .RealStatusNotReachable, .RealStatusUnknown:
            return SignalProducer<[Base], NetError>(error: .content)
        case .RealStatusViaWiFi, .RealStatusViaWWAN:
            if let account = api as? AccountAPI {
                let producer: SignalProducer<[Base], NetError> =
                    ProviderManager.shared.apiProvider
                        .request(account)
                        .toArray()
                return producer
            }
            else if let service = api as? ServiceAPI {
                let producer: SignalProducer<[Base], NetError> =
                    ProviderManager.shared.serviceProvider
                        .request(service)
                        .toArray()
                return producer
            }
            else {
                fatalError()
            }
        }
    }
}

五: 外界使用:

searchAction: Action<String, Void, NetError> = Action({ nick in
            return RequestManager<SessionUser>
            .requestArray(ServiceAPI.search(nickname: nick))
                .map({ sessionUsers in
                    self.result.value = sessionUsers.map { $0.user }
                    reloadObserver.send(value: ())
                })
        })
上一篇下一篇

猜你喜欢

热点阅读