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

一.首先定义一个总的遵守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: ())
                })
        })
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • AFHTTPRequestOperationManager 网络传输协议UDP、TCP、Http、Socket、X...
    Carden阅读 4,263评论 0 12
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,566评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • 近期,在直播节目《明日之子》中,薛之谦怒斥节目组黑幕,摔话筒愤然离去一度登上热搜。 薛之谦愤然离席后,一般人的反应...
    阿全不会文字阅读 562评论 0 3
  • 最开始听到这两个词,应该是小学吧,排队的时候,老师总是会说“ 男生一排,女生一排,按大小个儿站好,闭嘴”。...
    君子一诺陈苏阅读 545评论 0 0