需要导入RxAlamofire
pod 'RxAlamofire'
request(<#T##method: HTTPMethod##HTTPMethod#>, <#T##url: URLConvertible##URLConvertible#>, parameters: <#T##[String : Any]?#>, encoding: <#T##ParameterEncoding#>, headers: <#T##[String : String]?#>)
-
加载网络请求的几个方法:request、requestData、requestJSON、requestString
//创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)!
request(.get, url)
.data()
.subscribe(onNext: { (data) in
print(data)
}).disposed(by: disposeBag)
requestData(.post, url)
.subscribe(onNext: { (response, data) in
print(response)
print(data)
}).disposed(by: disposeBag)
requestJSON(.get, url)
.subscribe(onNext: { (response, json) in
print(json)
}).disposed(by: disposeBag)
requestString(.get, url)
.subscribe(onNext: { (response, str) in
print(response.allHeaderFields)
print(str)
}).disposed(by: disposeBag)
-
搭配HandyJSON,处理数据、模型转换
-
扩展HandyJSON,支持rx
-
import HandyJSON
import RxSwift
//数据映射错误
public enum RxMapModelError: Error {
case parsingError
}
//扩展Observable:增加模型映射方法
public extension Observable where Element:Any {
//将JSON数据转成对象
public func mapModel<T>(type:T.Type) -> Observable<T> where T:HandyJSON {
return self.map { (element) -> T in
guard let parsedElement = T.deserialize(from: element as? Dictionary) else {
throw RxMapModelError.parsingError
}
return parsedElement
}
}
//将JSON数据转成数组
public func mapModels<T>(type:T.Type) -> Observable<[T]> where T:HandyJSON {
return self.map { (element) -> [T] in
guard let parsedArray = [T].deserialize(from: element as? [Any]) else {
throw RxMapModelError.parsingError
}
return parsedArray as! [T]
}
}
}
-
事例代码
requestJSON(.get, url)
.map({ (response, json) -> Any in
print(json)
return json
})
.mapModel(type: MusicModel.self)
.subscribe(onNext: { (model) in
print(model.channels?.count ?? 1)
}).disposed(by: disposeBag)
-
文件上传:upload
-
使用文件流的形式上传文件
//需要上传的文件路径 let fileURL = Bundle.main.url(forResource: "hangge", withExtension: "zip") //服务器路径 let uploadURL = URL(string: "http://www.hangge.com/upload.php")! //将文件上传到服务器 upload(fileURL!, urlRequest: try! urlRequest(.post, uploadURL)) .subscribe(onCompleted: { print("上传完毕!") }) .disposed(by: disposeBag)
-
如何在上传时附带上文件名?
有时我们在文件上传的同时还会想要附带一些其它参数,比如文件名。这样服务端接收到文件后,就可以根据我们传过来的文件名来保存。实现这个其实很简单,客户端和服务端分别做如下修改。
客户端:将文件名以参数的形式跟在链接后面。比如:http://hangge.com/upload.php?fileName=image1.png
服务端:通过 $_GET["fileName"] 得到这个参数,并用其作为文件名保存。
-
获得上传进度
upload(fileURL!, urlRequest: try! urlRequest(.post, uploadURL))
.subscribe(onNext: { element in
print("--- 开始上传 ---")
element.uploadProgress(closure: { (progress) in
print("当前进度:\(progress.fractionCompleted)")
print(" 已上传载:\(progress.completedUnitCount/1024)KB")
print(" 总大小:\(progress.totalUnitCount/1024)KB")
})
}, onError: { error in
print("上传失败! 失败原因:\(error)")
}, onCompleted: {
print("上传完毕!")
})
.disposed(by: disposeBag)
upload(fileURL!, urlRequest: try! urlRequest(.post, uploadURL))
.map{request in
//返回一个关于进度的可观察序列
Observable<Float>.create{observer in
request.uploadProgress(closure: { (progress) in
observer.onNext(Float(progress.fractionCompleted))
if progress.isFinished{
observer.onCompleted()
}
})
return Disposables.create()
}
}
.flatMap{$0}
.bind(to: progressView.rx.progress) //将进度绑定UIProgressView上
.disposed(by: disposeBag)
-
上传 MultipartFormData 类型的文件数据(类似于网页上 Form 表单里的文件提交)
//需要上传的文件
let fileURL1 = Bundle.main.url(forResource: "0", withExtension: "png")
let fileURL2 = Bundle.main.url(forResource: "1", withExtension: "png")
//服务器路径
let uploadURL = URL(string: "http://www.hangge.com/upload2.php")!
//将文件上传到服务器
upload(
multipartFormData: { multipartFormData in
multipartFormData.append(fileURL1!, withName: "file1")
multipartFormData.append(fileURL2!, withName: "file2")
},
to: uploadURL,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .failure(let encodingError):
print(encodingError)
}
})
-
文本参数与文件一起提交(文件除了可以使用 fileURL,还可以上传 Data 类型的文件数据)
//字符串
let strData = "hangge.com".data(using: String.Encoding.utf8)
//数字
let intData = String(10).data(using: String.Encoding.utf8)
//文件1
let path = Bundle.main.url(forResource: "0", withExtension: "png")!
let file1Data = try! Data(contentsOf: path)
//文件2
let file2URL = Bundle.main.url(forResource: "1", withExtension: "png")
//服务器路径
let uploadURL = URL(string: "http://www.hangge.com/upload2.php")!
//将文件上传到服务器
upload(
multipartFormData: { multipartFormData in
multipartFormData.append(strData!, withName: "value1")
multipartFormData.append(intData!, withName: "value2")
multipartFormData.append(file1Data, withName: "file1",
fileName: "php.png", mimeType: "image/png")
multipartFormData.append(file2URL!, withName: "file2")
},
to: uploadURL,
encodingCompletion: { encodingResult in
switch encodingResult {
case .success(let upload, _, _):
// 上传进度
upload.uploadProgress(closure: { (progress) in
debugPrint(progress.fractionCompleted, progress.completedUnitCount / 1024, progress.totalUnitCount / 1024)
})
upload.responseJSON { response in
debugPrint(response)
}
case .failure(let encodingError):
print(encodingError)
}
})
-
文件下载
// 下载路径
let destination: DownloadRequest.DownloadFileDestination = { _, response in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// 文件名不变
// let fileURL = documentsURL.appendingPathComponent(response.suggestedFilename!)
// 自定义文件名
let fileURL = documentsURL.appendingPathComponent("file1/myLogo.png")
//两个参数表示如果有同名文件则会覆盖,如果路径中文件夹不存在则会自动创建
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
// 需要下载的文件
let fileURL = URL(string: "http://www.hangge.com/blog/images/logo.png")!
// 开始下载
download(URLRequest(url: fileURL), to: destination)
.subscribe(onNext: { element in
// 下载进度
element.downloadProgress(closure: { (progress) in
debugPrint(progress.fractionCompleted, progress.completedUnitCount / 1024, progress.totalUnitCount / 1024)
})
print("开始下载。")
}, onError: { error in
print("下载失败! 失败原因:\(error)")
}, onCompleted: {
print("下载完毕!")
})
.disposed(by: disposeBag)
-
使用默认提供的下载路径
Alamofire 内置的许多常用的下载路径方便我们使用,简化代码。注意的是,使用这种方式如果下载路径下有同名文件,不会覆盖原来的文件
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
-
下载进度
download(URLRequest(url: fileURL), to: destination)
.subscribe(onNext: { element in
print("开始下载。")
element.downloadProgress(closure: { progress in
print("当前进度: \(progress.fractionCompleted)")
print(" 已下载:\(progress.completedUnitCount/1024)KB")
print(" 总大小:\(progress.totalUnitCount/1024)KB")
})
}, onError: { error in
print("下载失败! 失败原因:\(error)")
}, onCompleted: {
print("下载完毕!")
}).disposed(by: disposeBag)
//开始下载
download(URLRequest(url: fileURL), to: destination)
.map{request in
//返回一个关于进度的可观察序列
Observable<Float>.create{observer in
request.downloadProgress(closure: { (progress) in
observer.onNext(Float(progress.fractionCompleted))
if progress.isFinished{
observer.onCompleted()
}
})
return Disposables.create()
}
}
.flatMap{$0}
.bind(to: progressView.rx.progress) //将进度绑定UIProgressView上
.disposed(by: disposeBag)
参考文章:Swift - RxSwift的使用详解45(结合RxAlamofire使用1:数据请求)
Swift - RxSwift的使用详解46(结合RxAlamofire使用2:结果处理、模型转换)
Swift - RxSwift的使用详解47(结合RxAlamofire使用3:文件上传)
Swift - RxSwift的使用详解48(结合RxAlamofire使用4:文件下载)
网友评论