swift4.0 -Moya使用(包含批量上傳圖片,請(qǐng)求出錯(cuò)或者業(yè)務(wù)統(tǒng)一處理)

學(xué)習(xí)目的

我只是出于對(duì)于這個(gè)框架的好奇,曾經(jīng)我在學(xué)習(xí)swift的時(shí)候,就是用的Alamofire,突然發(fā)現(xiàn)有一個(gè)很優(yōu)雅的第三方是基于這個(gè)向上封裝。并且,我很久沒(méi)有寫(xiě)swift了。

功能

本文包含了Moya的基本使用和圖片批量上傳(視頻等其它文件上傳跟圖片上傳類似)。并且應(yīng)用泛型實(shí)現(xiàn)了對(duì)返回結(jié)果統(tǒng)一做出處理,便于統(tǒng)一處理一些業(yè)務(wù)或者錯(cuò)誤。

  • 實(shí)現(xiàn)協(xié)議

LoginAPIManager文件包含一個(gè)登陸的請(qǐng)求,一個(gè)批量上傳圖片的請(qǐng)求(單張請(qǐng)自行做修改)。分別傳入了對(duì)應(yīng)的參數(shù),小伙伴可以根據(jù)自己需求去寫(xiě)這個(gè)枚舉。
這里啰嗦一下,請(qǐng)求的manager請(qǐng)做好分類,這樣找起來(lái)會(huì)方便很多,根據(jù)功能,或者根據(jù)模塊等都可以。

public enum LoginAPIManager {
    case login(name:String,password:String) //登錄
    case uploadPictures(paramsDic:NSMutableDictionary,dataAry:NSArray)  //上傳圖片
}

實(shí)現(xiàn)TargetType協(xié)議內(nèi)容,代碼中注釋很清楚了哈。

extension LoginAPIManager: TargetType {
    public var baseURL: URL {
        return URL(string: kBaseUrl)!   //這里是aip的base
    }
    
    public var path: String {
        switch self {
        case .login(_, _):
            return "登陸請(qǐng)求api"  //(這里請(qǐng)寫(xiě)上自己的api哦)
        case .uploadPictures(_, _):
            return "上傳圖片api"  //(這里請(qǐng)寫(xiě)上自己的api哦)
        }
       
    }
    //請(qǐng)求方式
    public var method: Moya.Method {
        return .post
    }

    //請(qǐng)求任務(wù)事件,帶上參數(shù)
    public var task: Task {
        switch self {
        case .login( let name, let password):
            return .requestParameters(parameters: ["userAccount": name,"initialPassword" : password], encoding: JSONEncoding.default)
        case .uploadPictures( let paramsDic, let dataAry):
            let formDataAry:NSMutableArray = NSMutableArray()
            for (index,image) in dataAry.enumerated() {
                //圖片轉(zhuǎn)成Data
                let data:Data = UIImageJPEGRepresentation(image as! UIImage, 0.9)!
                //根據(jù)當(dāng)前時(shí)間設(shè)置圖片上傳時(shí)候的名字
                let date:Date = Date()
                let formatter = DateFormatter()
                formatter.dateFormat = "yyyy-MM-dd-HH:mm:ss"
                var dateStr:String = formatter.string(from: date as Date)
                //別忘記這里給名字加上圖片的后綴哦
                dateStr = dateStr.appendingFormat("-%i.png", index)
                
                let formData = MultipartFormData(provider: .data(data), name: "file", fileName: dateStr, mimeType: "image/jpeg")
                formDataAry.add(formData)
            }
            return .uploadCompositeMultipart(formDataAry as! [MultipartFormData], urlParameters: paramsDic as! [String : Any])
//        default:
//            return .requestPlain    // 沒(méi)有參數(shù)
        }
    }
    
    //是否執(zhí)行Alamofire驗(yàn)證
//    public var validate: Bool {
//        return false
//    }
    
    //驗(yàn)證方式
    public var validationType: ValidationType {
        return .none
    }

    //這個(gè)就是做單元測(cè)試模擬的數(shù)據(jù),只會(huì)在單元測(cè)試文件中有作用
    public var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }
    
    //請(qǐng)求頭
    public var headers: [String: String]? {
        return nil
    }
}
  • 泛型實(shí)現(xiàn)返回結(jié)果統(tǒng)一處理

這里的endpointMapping是為了便于出錯(cuò)的情況下,清楚的知道這個(gè)請(qǐng)求的相關(guān)信息。

EDBaseAdapter這個(gè)文件,是用來(lái)對(duì)于請(qǐng)求的返回值,做統(tǒng)一處理的。在這個(gè)文件的
上層做一些緊密業(yè)務(wù)的處理,這里可以拋出問(wèn)題和做一些大家共同需要處理的業(yè)務(wù)或者錯(cuò)誤。

例如:這里可以做,如果你的項(xiàng)目session過(guò)期了,要統(tǒng)一彈出登錄頁(yè)面。還有業(yè)務(wù)出錯(cuò),錯(cuò)誤碼的解析,都可以放在這個(gè)文件里面。

這里實(shí)現(xiàn)思路是用泛型的概念,傳了枚舉作為參數(shù)的方法,生成一個(gè)實(shí)現(xiàn)了TargetType協(xié)議的類,從而去調(diào)用request方法。

這里的泛型我理解了很久,因?yàn)槲也恢罏槭裁次覀髁艘粋€(gè)LoginAPIManager里面的枚舉對(duì)象,就可以生成一個(gè)LoginAPIManager的Provider。后來(lái)我這樣理解,雖然我傳入的是一個(gè)LoginAPIManager的枚舉,但是實(shí)際上在生成MoyaProvider,用到的是LoginAPIManager實(shí)現(xiàn)的TargetType協(xié)議,枚舉泛指著LoginAPIManager這個(gè)類。個(gè)人理解,可能會(huì)不對(duì)哈。

private func endpointMapping<Target: TargetType>(target: Target) -> Endpoint {
    
    print("請(qǐng)求連接:\(target.baseURL)\(target.path) \n方法:\(target.method)\n參數(shù):\(String(describing: target.task)) ")
    return MoyaProvider.defaultEndpointMapping(for: target)
}
class EDBaseAdapter:NSObject {
    
    class func  request<T:TargetType>(
        _ target:T,success successCallback: @escaping (Any) -> Void,
        error errorCallback: @escaping (Int,String ) -> Void,
        failure failureCallback: @escaping (MoyaError) -> Void
        ) {
        let provider = MoyaProvider<T>(endpointClosure: endpointMapping,plugins:[])
        provider.request(target) { (result) in
        switch result {
            case let .success(response):
                do {
                    let data = try response.mapJSON()
                    let statusCode = response.statusCode
                    //在我的項(xiàng)目里,200和201是請(qǐng)求成功。
                    if (statusCode == 201 || statusCode == 200) {
                        //解析登錄數(shù)據(jù)
                        print("請(qǐng)求成功")
                        successCallback(data)
                    } else {
                        //請(qǐng)求報(bào)錯(cuò)提示,一般處理業(yè)務(wù)提示
                        print("請(qǐng)求出錯(cuò)了")
                        let dict = data
                        errorCallback(statusCode,(dict as AnyObject).object(forKey:"message") as! String)
                    }
                } catch {
                    //可不做處理
                }
                break
            case let .failure(error):
                print(error)
                failureCallback(error)
                break
            }
        }
    }
}

請(qǐng)求調(diào)用

下面的方法,我自己寫(xiě)完測(cè)試,是可以獲取到數(shù)據(jù)的。

        //登錄調(diào)用
        EDBaseAdapter.request(LoginAPIManager.login(name: self.userNameTextField.text!, password: self.passwordTextField.text!), success: { (data) in
            print(data)
        }, error: { (statutCode, message) in
            print(statutCode,message)
        }) { (error) in
            print(error)
        }
        
        //上傳圖片調(diào)用
        let paramsDic:NSMutableDictionary = NSMutableDictionary()
        paramsDic.setValue(0, forKey: "projectType")
        EDBaseAdapter.request(LoginAPIManager.uploadPictures(paramsDic: paramsDic, dataAry:NSArray.init(object: UIImage.init(named: "example")!)), success: { (data) in
            print(data)
        }, error: { (statutCode, message) in
            print(statutCode,message)
        }) { (error) in
            print(error)
        }

結(jié)尾

如果有什么問(wèn)題或者疑問(wèn),請(qǐng)告知我??赡芪一貜?fù)慢,或者不及時(shí)請(qǐng)諒解一下呢。但是態(tài)度絕對(duì)是很端正的。還有,妹子還是寫(xiě)OC的,swift邊寫(xiě)邊學(xué),不懂的再找資料。所以,描述或者用詞不準(zhǔn)確,請(qǐng)諒解同時(shí)請(qǐng)告知我,我看到會(huì)及時(shí)更正。希望能夠一起學(xué)習(xí)和一起進(jìn)步。
有一個(gè)簡(jiǎn)單的工程,里面包含了這些文件。是我隨手寫(xiě)的一個(gè)登陸的界面,登錄事件里面調(diào)用了文中登錄和上傳圖片的方法。
鏈接:https://pan.baidu.com/s/132XqsEzdEV0q0A2SiIdbJQ 密碼:0m51

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容