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

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

作者: flyrr | 来源:发表于2017-06-05 17:49 被阅读86次

    一.首先定义一个总的遵守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: ())
                    })
            })
    

    相关文章

      网友评论

          本文标题:分享一个自用的带Rac扩展的Moya网络请求工具类

          本文链接:https://www.haomeiwen.com/subject/fdxwfxtx.html