swift4.0 -Moya使用(包含批量上傳圖片,請求出錯或者業務統一處理)

學習目的

我只是出于對于這個框架的好奇,曾經我在學習swift的時候,就是用的Alamofire,突然發現有一個很優雅的第三方是基于這個向上封裝。并且,我很久沒有寫swift了。

功能

本文包含了Moya的基本使用和圖片批量上傳(視頻等其它文件上傳跟圖片上傳類似)。并且應用泛型實現了對返回結果統一做出處理,便于統一處理一些業務或者錯誤。

  • 實現協議

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

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

實現TargetType協議內容,代碼中注釋很清楚了哈。

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

    //請求任務事件,帶上參數
    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() {
                //圖片轉成Data
                let data:Data = UIImageJPEGRepresentation(image as! UIImage, 0.9)!
                //根據當前時間設置圖片上傳時候的名字
                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    // 沒有參數
        }
    }
    
    //是否執行Alamofire驗證
//    public var validate: Bool {
//        return false
//    }
    
    //驗證方式
    public var validationType: ValidationType {
        return .none
    }

    //這個就是做單元測試模擬的數據,只會在單元測試文件中有作用
    public var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }
    
    //請求頭
    public var headers: [String: String]? {
        return nil
    }
}
  • 泛型實現返回結果統一處理

這里的endpointMapping是為了便于出錯的情況下,清楚的知道這個請求的相關信息。

EDBaseAdapter這個文件,是用來對于請求的返回值,做統一處理的。在這個文件的
上層做一些緊密業務的處理,這里可以拋出問題和做一些大家共同需要處理的業務或者錯誤。

例如:這里可以做,如果你的項目session過期了,要統一彈出登錄頁面。還有業務出錯,錯誤碼的解析,都可以放在這個文件里面。

這里實現思路是用泛型的概念,傳了枚舉作為參數的方法,生成一個實現了TargetType協議的類,從而去調用request方法。

這里的泛型我理解了很久,因為我不知道為什么我傳了一個LoginAPIManager里面的枚舉對象,就可以生成一個LoginAPIManager的Provider。后來我這樣理解,雖然我傳入的是一個LoginAPIManager的枚舉,但是實際上在生成MoyaProvider,用到的是LoginAPIManager實現的TargetType協議,枚舉泛指著LoginAPIManager這個類。個人理解,可能會不對哈。

private func endpointMapping<Target: TargetType>(target: Target) -> Endpoint {
    
    print("請求連接:\(target.baseURL)\(target.path) \n方法:\(target.method)\n參數:\(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
                    //在我的項目里,200和201是請求成功。
                    if (statusCode == 201 || statusCode == 200) {
                        //解析登錄數據
                        print("請求成功")
                        successCallback(data)
                    } else {
                        //請求報錯提示,一般處理業務提示
                        print("請求出錯了")
                        let dict = data
                        errorCallback(statusCode,(dict as AnyObject).object(forKey:"message") as! String)
                    }
                } catch {
                    //可不做處理
                }
                break
            case let .failure(error):
                print(error)
                failureCallback(error)
                break
            }
        }
    }
}

請求調用

下面的方法,我自己寫完測試,是可以獲取到數據的。

        //登錄調用
        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)
        }
        
        //上傳圖片調用
        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)
        }

結尾

如果有什么問題或者疑問,請告知我。可能我回復慢,或者不及時請諒解一下呢。但是態度絕對是很端正的。還有,妹子還是寫OC的,swift邊寫邊學,不懂的再找資料。所以,描述或者用詞不準確,請諒解同時請告知我,我看到會及時更正。希望能夠一起學習和一起進步。
有一個簡單的工程,里面包含了這些文件。是我隨手寫的一個登陸的界面,登錄事件里面調用了文中登錄和上傳圖片的方法。
鏈接:https://pan.baidu.com/s/132XqsEzdEV0q0A2SiIdbJQ 密碼:0m51

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容