美文网首页Swift学习
RxAlamofire的使用

RxAlamofire的使用

作者: FallPine | 来源:发表于2018-09-12 10:19 被阅读167次

需要导入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:文件下载)

相关文章

  • RxAlamofire的使用

    需要导入RxAlamofire pod 'RxAlamofire' 加载网络请求的几个方法:request、req...

  • Swift - RxSwift的使用详解47(结合RxAlamo

    六、文件上传 1,支持的上传类型 Alamofire 支持如下上传类型,使用 RxAlamofire 也是一样的:...

  • RxAlamofire 的 rx.json 与 Codable

    网上有很多基于rx.data 方法的,或者responseXXX的,不采用那些方法的原因是,那些方法不支持 sta...

  • iconfont的使用(下载使用)

    1、下载文件 2、在生命周期中引入项目 beforeCreate () { var domModule = ...

  • Gson的使用--使用注解

    Gson为了简化序列化和反序列化的过程,提供了很多注解,这些注解大致分为三类,我们一一的介绍一下。 自定义字段的名...

  • 记录使用iframe的使用

    默认记录一下----可以说 这是我第一次使用iframe 之前都没有使用过; 使用方式: 自己开发就用了这几个属...

  • with的使用

    下面例子可以具体说明with如何工作: 运行代码,输出如下

  • this的使用

    什么是this? this是一个关键字,这个关键字总是返回一个对象;简单说,就是返回属性或方法“当前”所在的对象。...

  • this的使用

    JS中this调用有几种情况 一:纯粹的函数调用 这是函数的最通常用法,属于全局性调用,因此this就代表全局对象...

  • ==的使用

    积累日常遇到的编码规范,良好的编码习惯,持续更新。。。 日常使用==用于判断的时候,习惯性将比较值写前面,变量写后...

网友评论

    本文标题:RxAlamofire的使用

    本文链接:https://www.haomeiwen.com/subject/mtuugftx.html