學習目的
我只是出于對于這個框架的好奇,曾經(jīng)我在學習swift的時候,就是用的Alamofire,突然發(fā)現(xiàn)有一個很優(yōu)雅的第三方是基于這個向上封裝。并且,我很久沒有寫swift了。
功能
本文包含了Moya的基本使用和圖片批量上傳(視頻等其它文件上傳跟圖片上傳類似)。并且應用泛型實現(xiàn)了對返回結(jié)果統(tǒng)一做出處理,便于統(tǒng)一處理一些業(yè)務或者錯誤。
-
實現(xiàn)協(xié)議
LoginAPIManager文件包含一個登陸的請求,一個批量上傳圖片的請求(單張請自行做修改)。分別傳入了對應的參數(shù),小伙伴可以根據(jù)自己需求去寫這個枚舉。
這里啰嗦一下,請求的manager請做好分類,這樣找起來會方便很多,根據(jù)功能,或者根據(jù)模塊等都可以。
public enum LoginAPIManager {
case login(name:String,password:String) //登錄
case uploadPictures(paramsDic:NSMutableDictionary,dataAry:NSArray) //上傳圖片
}
實現(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 "登陸請求api" //(這里請寫上自己的api哦)
case .uploadPictures(_, _):
return "上傳圖片api" //(這里請寫上自己的api哦)
}
}
//請求方式
public var method: Moya.Method {
return .post
}
//請求任務事件,帶上參數(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ù)當前時間設置圖片上傳時候的名字
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 // 沒有參數(shù)
}
}
//是否執(zhí)行Alamofire驗證
// public var validate: Bool {
// return false
// }
//驗證方式
public var validationType: ValidationType {
return .none
}
//這個就是做單元測試模擬的數(shù)據(jù),只會在單元測試文件中有作用
public var sampleData: Data {
return "{}".data(using: String.Encoding.utf8)!
}
//請求頭
public var headers: [String: String]? {
return nil
}
}
-
泛型實現(xiàn)返回結(jié)果統(tǒng)一處理
這里的endpointMapping是為了便于出錯的情況下,清楚的知道這個請求的相關信息。
EDBaseAdapter這個文件,是用來對于請求的返回值,做統(tǒng)一處理的。在這個文件的
上層做一些緊密業(yè)務的處理,這里可以拋出問題和做一些大家共同需要處理的業(yè)務或者錯誤。
例如:這里可以做,如果你的項目session過期了,要統(tǒng)一彈出登錄頁面。還有業(yè)務出錯,錯誤碼的解析,都可以放在這個文件里面。
這里實現(xiàn)思路是用泛型的概念,傳了枚舉作為參數(shù)的方法,生成一個實現(xiàn)了TargetType協(xié)議的類,從而去調(diào)用request方法。
這里的泛型我理解了很久,因為我不知道為什么我傳了一個LoginAPIManager里面的枚舉對象,就可以生成一個LoginAPIManager的Provider。后來我這樣理解,雖然我傳入的是一個LoginAPIManager的枚舉,但是實際上在生成MoyaProvider,用到的是LoginAPIManager實現(xiàn)的TargetType協(xié)議,枚舉泛指著LoginAPIManager這個類。個人理解,可能會不對哈。
private func endpointMapping<Target: TargetType>(target: Target) -> Endpoint {
print("請求連接:\(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
//在我的項目里,200和201是請求成功。
if (statusCode == 201 || statusCode == 200) {
//解析登錄數(shù)據(jù)
print("請求成功")
successCallback(data)
} else {
//請求報錯提示,一般處理業(yè)務提示
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
}
}
}
}
請求調(diào)用
下面的方法,我自己寫完測試,是可以獲取到數(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é)尾
如果有什么問題或者疑問,請告知我。可能我回復慢,或者不及時請諒解一下呢。但是態(tài)度絕對是很端正的。還有,妹子還是寫OC的,swift邊寫邊學,不懂的再找資料。所以,描述或者用詞不準確,請諒解同時請告知我,我看到會及時更正。希望能夠一起學習和一起進步。
有一個簡單的工程,里面包含了這些文件。是我隨手寫的一個登陸的界面,登錄事件里面調(diào)用了文中登錄和上傳圖片的方法。
鏈接:https://pan.baidu.com/s/132XqsEzdEV0q0A2SiIdbJQ 密碼:0m51