ReactiveX 学习笔记(17)使用 RxSwift + Alamofire 调用 REST API
JSON : Placeholder
JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站。
以下使用 RxSwift + Alamofire 调用该网站的 REST API,获取字符串以及 JSON 数据。
- GET /posts/1
- GET /posts
- POST /posts
- PUT /posts/1
- DELETE /posts/1
所有 GET API 都返回JSON数据,格式(JSON-Schema)如下:
{
"type":"object",
"properties": {
"userId": {"type" : "integer"},
"id": {"type" : "integer"},
"title": {"type" : "string"},
"body": {"type" : "string"}
}
}
创建工程
打开 Xcode,File / New / Project..
在 New Project 向导的第1页,选 iOS / Single View App
在向导的第2页填上 Product Name: RxExample
在向导的第3页选择任意文件夹点击 Create 按钮创建工程
关闭所创建的工程
配置 Pods
在工程所在文件夹下创建 Podfile 文件,内容如下:
workspace 'RxExample'
use_frameworks!
target 'RxExample' do
project 'RxExample'
pod 'CodableAlamofire'
pod 'RxAlamofire'
end
打开终端在工程所在文件夹下执行 pod install 命令。
$ cd RxExample
$ pod install
...
Installing Alamofire (4.7.3)
Installing CodableAlamofire (1.1.0)
Installing RxAlamofire (4.2.0)
Installing RxSwift (4.2.0)
...
用 Xcode 打开 RxExample.xcworkspace
RxCodableAlamofire
在 RxExample 工程中添加 RxCodableAlamofire.swift 文件,内容如下:
import Foundation
import RxSwift
import Alamofire
import RxAlamofire
import CodableAlamofire
class RxCodableAlamofire {
public static func object<T: Decodable>(_ method: Alamofire.HTTPMethod, _ url: URLConvertible, parameters: [String: Any]? = nil, encoding: ParameterEncoding = URLEncoding.default, headers: [String: String]? = nil, queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, decoder: JSONDecoder = JSONDecoder()) -> Observable<T> {
return SessionManager.default.rx.object(method, url, parameters: parameters, encoding: encoding, headers: headers, queue: queue, keyPath: keyPath, mapToObject: object, decoder: decoder)
}
}
extension Reactive where Base: SessionManager {
public func object<T: Decodable>(_ method: Alamofire.HTTPMethod, _ url: URLConvertible, parameters: [String: Any]? = nil, encoding: ParameterEncoding = URLEncoding.default, headers: [String: String]? = nil, queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, decoder: JSONDecoder = JSONDecoder()) -> Observable<T> {
return request(method, url, parameters: parameters, encoding: encoding, headers: headers).flatMap { $0.rx.object(queue: queue, keyPath: keyPath, mapToObject: object, decoder: decoder) }
}
}
extension Reactive where Base: DataRequest {
public func object<T: Decodable>(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, decoder: JSONDecoder = JSONDecoder()) -> Observable<T> {
return result(queue: queue, responseSerializer: DataRequest.DecodableObjectSerializer(keyPath, decoder))
}
}
在 Pods 工程中找到并打开 DataRequest+Decodable.swift (Pods/CodableAlamofire)
将其中的 DecodableObjectSerializer 的可见性从 private 改为 public。(提示是否 unlock 时按下 Unlock)
RestApi
在 RxExample 工程中添加 RestApi.swift 文件,内容如下:
import Foundation
import Alamofire
import RxSwift
import RxAlamofire
// https://stackoverflow.com/questions/27855319/post-request-with-a-simple-string-in-body-with-alamofire
class StringEncoding: ParameterEncoding {
let body: String;
public init(body: String) {
self.body = body
}
public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var request = try urlRequest.asURLRequest()
request.httpBody = body.data(using: .utf8, allowLossyConversion: false)
return request
}
}
extension Encodable {
public func toJSONString(prettyPrint: Bool) throws -> String? {
let encoder = JSONEncoder()
if prettyPrint { encoder.outputFormatting = .prettyPrinted }
let data = try! encoder.encode(self)
let jsonString = String(data: data, encoding: .utf8)
return jsonString
}
}
class RestApi {
static func getObject<T: Decodable>(url: String, keyPath: String? = nil) -> Observable<T> {
return RxCodableAlamofire.object(.get, url, keyPath: keyPath)
}
static func getArray<T: Decodable>(url: String, keyPath: String? = nil) -> Observable<[T]> {
return RxCodableAlamofire.object(.get, url, keyPath: keyPath)
}
static func update(url: String, body: String) -> Observable<String> {
return RxAlamofire.string(.put, url, encoding: StringEncoding(body: body))
}
static func create(url: String, body: String) -> Observable<String> {
return RxAlamofire.string(.post, url, encoding: StringEncoding(body: body))
}
static func delete(url: String) -> Observable<String> {
return RxAlamofire.string(.delete, url)
}
static func getString(url: String) -> Observable<String> {
return RxAlamofire.string(.get, url)
}
}
Post
在 RxExample 工程中添加 Post.swift 文件,内容如下:
import Foundation
import RxSwift
struct Post : Codable {
let userId: Int
let id: Int
let title: String
let body: String
var description: String {
return "Post {userId = \(userId), id = \(id), title = \"\(title)\", body = \"\(body.replacingOccurrences(of: "\n", with: "\\n"))\"}";
}
static let url = "https://jsonplaceholder.typicode.com/"
static func getPostAsString() -> Observable<String> {
return RestApi.getString(url: "\(url)posts/1")
}
static func getPostAsJson() -> Observable<Post> {
return RestApi.getObject(url: "\(url)posts/1")
}
static func getPosts(n: Int) -> Observable<Post> {
return RestApi.getArray(url: "\(url)posts").flatMap { Observable.from($0) }.take(n)
}
static func createPost() -> Observable<String> {
let post = Post(userId: 101, id: 0, title: "test title", body: "test body")
return RestApi.create(url: "\(url)posts", body: try! post.toJSONString(prettyPrint: false)!)
}
static func updatePost() -> Observable<String> {
let post = Post(userId: 101, id: 1, title: "test title", body: "test body")
return RestApi.update(url: "\(url)posts/1", body: try! post.toJSONString(prettyPrint: false)!)
}
static func deletePost() -> Observable<String> {
return RestApi.delete(url: "\(url)posts/1")
}
}
- getPostAsString 方法取出第1个Post,返回字符串
- getPostAsJson 方法取出第1个Post,返回Post对象
- getPosts 方法取出前n个Post,返回n个Post对象
- createPost 方法创建1个Post,返回字符串
- updatePost 方法更新第1个Post,返回字符串
- deletePost 方法删除第1个Post,返回字符串
AppDelegate
在 AppDelegate.swift 中添加 RxSwift 的引用,然后在 AppDelegate 类中添加 DisposeBag 类型的实例。
import RxSwift
class AppDelegate {
// ...
let disposeBag = DisposeBag()
// ...
}
在 AppDelegate 类的 applicationDidFinishLaunching 方法中添加以下代码
Post.getPostAsString().do(onNext: { print($0) }).subscribe().disposed(by: disposeBag)
Post.getPostAsJson().do(onNext: { print($0.description) }).subscribe().disposed(by: disposeBag)
Post.getPosts(n: 2).do(onNext: { print($0.description) }).subscribe().disposed(by: disposeBag)
Post.createPost().do(onNext: { print($0) }).subscribe().disposed(by: disposeBag)
Post.updatePost().do(onNext: { print($0) }).subscribe().disposed(by: disposeBag)
Post.deletePost().do(onNext: { print($0) }).subscribe().disposed(by: disposeBag)
输出结果
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
Post {userId = 1, id = 2, title = "qui est esse", body = "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla"}
Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"}
{}
{
"{\"body\":\"test body\",\"id\":0,\"title\":\"test title\",\"userId\":101}": "",
"id": 101
}
{
"id": 1
}
ReactiveX 学习笔记(17)使用 RxSwift + Alamofire 调用 REST API的更多相关文章
- ReactiveX 学习笔记(0)学习资源
ReactiveX 学习笔记 ReactiveX 学习笔记(1) ReactiveX 学习笔记(2)创建数据流 ReactiveX 学习笔记(3)转换数据流 ReactiveX 学习笔记(4)过滤数据 ...
- Ext.Net学习笔记17:Ext.Net GridPanel Selection
Ext.Net学习笔记17:Ext.Net GridPanel Selection 接下来是Ext.Net的GridPanel的另外一个功能:选择. 我们在GridPanel最开始的用法中已经见识过如 ...
- Memcached 学习笔记(二)——ruby调用
Memcached 学习笔记(二)——ruby调用 上一节我们讲述了怎样安装memcached及memcached常用命令.这一节我们将通过ruby来调用memcached相关操作. 第一步,安装ru ...
- SQL反模式学习笔记17 全文搜索
目标:全文搜索 使用SQL搜索关键字,同时保证快速和精确,依旧是相当地困难. SQL的一个基本原理(以及SQL所继承的关系原理)就是一列中的单个数据是原子性的. 反模式:模式匹配 使用Like 或者正 ...
- golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍
golang学习笔记17 爬虫技术路线图,python,java,nodejs,go语言,scrapy主流框架介绍 go语言爬虫框架:gocolly/colly,goquery,colly,chrom ...
- python3.4学习笔记(二十五) Python 调用mysql redis实例代码
python3.4学习笔记(二十五) Python 调用mysql redis实例代码 #coding: utf-8 __author__ = 'zdz8207' #python2.7 import ...
- Hadoop源码学习笔记(4) ——Socket到RPC调用
Hadoop源码学习笔记(4) ——Socket到RPC调用 Hadoop是一个分布式程序,分布在多台机器上运行,事必会涉及到网络编程.那这里如何让网络编程变得简单.透明的呢? 网络编程中,首先我们要 ...
- ReactiveX 学习笔记(14)使用 RxJava2 + Retrofit2 调用 REST API
JSON : Placeholder JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站. ...
- [原创]java WEB学习笔记17:关于中文乱码的问题 和 tomcat在eclipse中起动成功,主页却打不开
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
随机推荐
- [UE4]最简单的虚幻4网络游戏,使用虚幻4内置服务器
一.设置游戏窗口合适的大小 二.在新窗口中运行游戏.玩家数量改成大于1. 三.运行游戏就会打开多个窗口 在打包完成的游戏中进行网络游戏: 一.虚幻4打包好的文件是放在WindowsNoEditor ...
- CRM N:1 关系或者字段无法删除
点开详细信息查看那些实体引用了该组件.查看内容如下: 1 查看窗体上有无该字段; 2 查看视图中有无该字段; 3 查看试图的 筛选条件; 4 查看试图的 查找列; 5 发布之后再试试.
- easyUI的combotree的树的懒加载。
var tree=[{ "id":1, "text":"My Documents", "children&quo ...
- gulp 编译es6 react 教程 案例 配置
1.gulp基本配置: var gulp = require('gulp'), watch = require('gulp-watch'), babel = require('gulp-babel') ...
- Fragment重叠,使用show和hide控制显示和隐藏界面重叠问题;
Fragment重叠原因: App因某种原因崩溃自动重启,或App长期在后台运行Fragment依赖的activity被回收等等原因:当系统内存不足,Fragment 的依附Activity 被回收的 ...
- python连接RabbitMQ
安装PIP wget "https://pypi.python.org/packages/source/p/pip/pip-1.5.4.tar.gz tar -xzvf pip-.tar.g ...
- 在html中使用thymeleaf编写通用模块
在编写页面时,常常会需要用到通用模块,比如header部分.footer部分等. 项目前端使用的是themeleaf模板引擎,下面简单介绍下使用themeleaf写header通用模块: 1. 通用部 ...
- day10学习笔记整理
函数对象函数是第一类对象: 指的是函数名指向的值(函数)可以被当作数据去使用 1. 可以被引用 2. 可以当作参数传给另外一个函数 3. 可以当作一个函数的返回值 4. 可以当作容器类型的元素 l ...
- Docker使用札记 - 使用中遇到的问题总结
1. 启动容器时报错误“: No such file or directory” 一般来说作为容器应用的入口都是entrypoint.sh文件,也就是Dockerfile最后一条指令为是: ENTRY ...
- 安装python的jupyter notebook工具
jupyter notebook是一个通过网页运行python的工具 支持分段的python运行,并能直观的查看结果 支持多python环境运行,需要加装(conda) 安装步骤 1.安装python ...