一、请求网络数据

① 通过 rx.response 请求数据

  • 如下所示,通过豆瓣提供的音乐频道列表接口获取数据,并将返回结果输出到控制台中:
"https://www.douban.com/j/app/radio/channels" -i -v
Success (2134ms): Status 200
返回的数据是: {"channels":[{"name_en":"Personal Radio","seq_id":0,"abbr_en":"My","name":"私人兆赫","channel_id":0},{"name":"华语","seq_id":0,"abbr_en":"","channel_id":"1","name_en":""},{"name":"欧美","seq_id":1,"abbr_en":"","channel_id":"2","name_en":""},{"name":"七零","seq_id":2,"abbr_en":"","channel_id":"3","name_en":""},{"name":"八零","seq_id":3,"abbr_en":"","channel_id":"4","name_en":""},{"name":"九零","seq_id":4,"abbr_en":"","channel_id":"5","name_en":""},{"name":"粤语","seq_id":5,"abbr_en":"","channel_id":"6","name_en":""},{"name":"摇滚","seq_id":6,"abbr_en":"","channel_id":"7","name_en":""},{"name":"民谣","seq_id":7,"abbr_en":"","channel_id":"8","name_en":""},{"name":"轻音乐","seq_id":8,"abbr_en":"","channel_id":"9","name_en":""},{"name":"原声","seq_id":9,"abbr_en":"","channel_id":"10","name_en":""},{"name":"Fly by midnight ","seq_id":10,"abbr_en":"","channel_id":"267","name_en":""},{"name":"独立","seq_id":11,"abbr_en":"","channel_id":"268","name_en":""},{"name":"爵士","seq_id":12,"abbr_en":"","channel_id":"13","name_en":""},{"name":"电子","seq_id":13,"abbr_en":"","channel_id":"14","name_en":""},{"name":"说唱","seq_id":14,"abbr_en":"","channel_id":"15","name_en":""},{"name":"R&B ","seq_id":15,"abbr_en":"","channel_id":"16","name_en":""},{"name":"日语","seq_id":16,"abbr_en":"","channel_id":"17","name_en":""},{"name":"韩语","seq_id":17,"abbr_en":"","channel_id":"18","name_en":""},{"name":"我的巴比伦恋人","seq_id":18,"abbr_en":"","channel_id":"259","name_en":""},{"name":"女声","seq_id":19,"abbr_en":"","channel_id":"20","name_en":""},{"name":"法语","seq_id":20,"abbr_en":"","channel_id":"22","name_en":""},{"name":"户外","seq_id":21,"abbr_en":"","channel_id":"151","name_en":""},{"name":"休息","seq_id":22,"abbr_en":"","channel_id":"152","name_en":""},{"name":"工作学习","seq_id":23,"abbr_en":"","channel_id":"153","name_en":""},{"name":"亢奋","seq_id":24,"abbr_en":"","channel_id":"154","name_en":""},{"name":"古典","seq_id":25,"abbr_en":"","channel_id":"27","name_en":""},{"name":"动漫","seq_id":26,"abbr_en":"","channel_id":"28","name_en":""},{"name":"咖啡馆","seq_id":27,"abbr_en":"","channel_id":"32","name_en":""},{"name":"舒缓","seq_id":28,"abbr_en":"","channel_id":"155","name_en":""},{"name":"18岁青春的召唤","seq_id":29,"abbr_en":"","channel_id":"262","name_en":""},{"name":"红歌","seq_id":30,"abbr_en":"","channel_id":"41","name_en":""},{"name":"圣诞","seq_id":31,"abbr_en":"","channel_id":"170","name_en":""},{"name":"运动","seq_id":32,"abbr_en":"","channel_id":"257","name_en":""},{"name":"英语","seq_id":33,"abbr_en":"","channel_id":"264","name_en":""},{"name":"豆瓣好歌曲","seq_id":34,"abbr_en":"","channel_id":"179","name_en":""},{"name":"Future Pop","seq_id":35,"abbr_en":"","channel_id":"266","name_en":""},{"name":"金属","seq_id":36,"abbr_en":"","channel_id":"187","name_en":""},{"name":"布鲁斯","seq_id":37,"abbr_en":"","channel_id":"188","name_en":""},{"name":"新歌","seq_id":38,"abbr_en":"","channel_id":"61","name_en":""},{"name":"世界杯","seq_id":39,"abbr_en":"","channel_id":"201","name_en":""},{"name":"朋克","seq_id":40,"abbr_en":"","channel_id":"76","name_en":""},{"name":"Easy ","seq_id":41,"abbr_en":"","channel_id":"77","name_en":""},{"name":"91.1 ","seq_id":42,"abbr_en":"","channel_id":"78","name_en":""},{"name":"乡村","seq_id":43,"abbr_en":"","channel_id":"269","name_en":""},{"name":"“砖”属音乐","seq_id":44,"abbr_en":"","channel_id":"145","name_en":""},{"name":"Pop","seq_id":45,"abbr_en":"","channel_id":"194","name_en":""},{"name":"拉丁","seq_id":46,"abbr_en":"","channel_id":"189","name_en":""}]}
  • 请求示例如下:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.response(request: request).subscribe(onNext: {(response, data) in// 数据处理let str = String(data: data, encoding: String.Encoding.utf8)print("返回的数据是:", str ?? "")
}).disposed(by: disposeBag)
  • 从以上示例,可以看到,不管请求成功与否都会进入到 onNext 这个回调中,如果需要根据响应状态进行一些相应操作,比如:
    • 状态码在 200 ~ 300 则正常显示数据;
    • 如果是异常状态码(比如:404)则弹出告警提示框。
  • 可以借助 response 参数进行判断即可,把 url 改成一个错误的地址:
// 创建URL对象
let urlString = "https://www.douban.com/xxxxxxxxxx/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.response(request: request).subscribe(onNext: {(response, data) in// 判断响应结果状态码if 200 ..< 300 ~= response.statusCode {let str = String(data: data, encoding: String.Encoding.utf8)print("请求成功!返回的数据是:", str ?? "")}else{print("请求失败!")}
}).disposed(by: disposeBag)
  • 运行结果如下:
curl -X GET
"https://www.douban.com/xxxxxxxxxx/app/radio/channels" -i -v
Failure (1448ms): Status 404
请求失败!

② 通过 rx.data 请求数据

  • rx.data 与 rx.response 的区别:
    • 如果不需要获取底层的 response,只需知道请求是否成功,以及成功时返回的结果,那么建议使用 rx.data。
    • 因为 rx.data 会自动对响应状态码进行判断,只有成功的响应(状态码为 200~300)才会进入到 onNext 这个回调,否则进入 onError 这个回调。
  • 如果不需要考虑请求失败的情况,只对成功返回的结果做处理可以在 onNext 回调中进行相关操作:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.data(request: request).subscribe(onNext: {data inlet str = String(data: data, encoding: String.Encoding.utf8)print("请求成功!返回的数据是:", str ?? "")
}).disposed(by: disposeBag)
  • 运行结果:
"https://www.douban.com/j/app/radio/channels" -i -v
Success (1449ms): Status 200
请求成功!返回的数据是: {"channels":[{"name_en":"Personal Radio","seq_id":0,"abbr_en":"My","name":"私人兆赫","channel_id":0},{"name":"华语","seq_id":0,"abbr_en":"","channel_id":"1","name_en":""},{"name":"欧美","seq_id":1,"abbr_en":"","channel_id":"2","name_en":""},{"name":"七零","seq_id":2,"abbr_en":"","channel_id":"3","name_en":""},{"name":"八零","seq_id":3,"abbr_en":"","channel_id":"4","name_en":""},{"name":"九零","seq_id":4,"abbr_en":"","channel_id":"5","name_en":""},{"name":"粤语","seq_id":5,"abbr_en":"","channel_id":"6","name_en":""},{"name":"摇滚","seq_id":6,"abbr_en":"","channel_id":"7","name_en":""},{"name":"民谣","seq_id":7,"abbr_en":"","channel_id":"8","name_en":""},{"name":"轻音乐","seq_id":8,"abbr_en":"","channel_id":"9","name_en":""},{"name":"原声","seq_id":9,"abbr_en":"","channel_id":"10","name_en":""},{"name":"Fly by midnight ","seq_id":10,"abbr_en":"","channel_id":"267","name_en":""},{"name":"独立","seq_id":11,"abbr_en":"","channel_id":"268","name_en":""},{"name":"爵士","seq_id":12,"abbr_en":"","channel_id":"13","name_en":""},{"name":"电子","seq_id":13,"abbr_en":"","channel_id":"14","name_en":""},{"name":"说唱","seq_id":14,"abbr_en":"","channel_id":"15","name_en":""},{"name":"R&B ","seq_id":15,"abbr_en":"","channel_id":"16","name_en":""},{"name":"日语","seq_id":16,"abbr_en":"","channel_id":"17","name_en":""},{"name":"韩语","seq_id":17,"abbr_en":"","channel_id":"18","name_en":""},{"name":"我的巴比伦恋人","seq_id":18,"abbr_en":"","channel_id":"259","name_en":""},{"name":"女声","seq_id":19,"abbr_en":"","channel_id":"20","name_en":""},{"name":"法语","seq_id":20,"abbr_en":"","channel_id":"22","name_en":""},{"name":"户外","seq_id":21,"abbr_en":"","channel_id":"151","name_en":""},{"name":"休息","seq_id":22,"abbr_en":"","channel_id":"152","name_en":""},{"name":"工作学习","seq_id":23,"abbr_en":"","channel_id":"153","name_en":""},{"name":"亢奋","seq_id":24,"abbr_en":"","channel_id":"154","name_en":""},{"name":"古典","seq_id":25,"abbr_en":"","channel_id":"27","name_en":""},{"name":"动漫","seq_id":26,"abbr_en":"","channel_id":"28","name_en":""},{"name":"咖啡馆","seq_id":27,"abbr_en":"","channel_id":"32","name_en":""},{"name":"舒缓","seq_id":28,"abbr_en":"","channel_id":"155","name_en":""},{"name":"18岁青春的召唤","seq_id":29,"abbr_en":"","channel_id":"262","name_en":""},{"name":"红歌","seq_id":30,"abbr_en":"","channel_id":"41","name_en":""},{"name":"圣诞","seq_id":31,"abbr_en":"","channel_id":"170","name_en":""},{"name":"运动","seq_id":32,"abbr_en":"","channel_id":"257","name_en":""},{"name":"英语","seq_id":33,"abbr_en":"","channel_id":"264","name_en":""},{"name":"豆瓣好歌曲","seq_id":34,"abbr_en":"","channel_id":"179","name_en":""},{"name":"Future Pop","seq_id":35,"abbr_en":"","channel_id":"266","name_en":""},{"name":"金属","seq_id":36,"abbr_en":"","channel_id":"187","name_en":""},{"name":"布鲁斯","seq_id":37,"abbr_en":"","channel_id":"188","name_en":""},{"name":"新歌","seq_id":38,"abbr_en":"","channel_id":"61","name_en":""},{"name":"世界杯","seq_id":39,"abbr_en":"","channel_id":"201","name_en":""},{"name":"朋克","seq_id":40,"abbr_en":"","channel_id":"76","name_en":""},{"name":"Easy ","seq_id":41,"abbr_en":"","channel_id":"77","name_en":""},{"name":"91.1 ","seq_id":42,"abbr_en":"","channel_id":"78","name_en":""},{"name":"乡村","seq_id":43,"abbr_en":"","channel_id":"269","name_en":""},{"name":"“砖”属音乐","seq_id":44,"abbr_en":"","channel_id":"145","name_en":""},{"name":"Pop","seq_id":45,"abbr_en":"","channel_id":"194","name_en":""},{"name":"拉丁","seq_id":46,"abbr_en":"","channel_id":"189","name_en":""}]}
  • 如果还要处理失败的情况,可以在 onError 回调中操作:
// 创建URL对象
let urlString = "https://www.douban.com/xxxxxx/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.data(request: request).subscribe(onNext: {data inlet str = String(data: data, encoding: String.Encoding.utf8)print("请求成功!返回的数据是:", str ?? "")
}, onError: { error inprint("请求失败!错误原因:", error)
}).disposed(by: disposeBag)
  • 运行结果:
"https://www.douban.com/xxxxxx/app/radio/channels" -i -v
Failure (7189ms): Status 404
请求失败!错误原因: HTTP request failed with `404`.

二、手动发起请求和取消请求

  • 在很多情况下,网络请求并不是由程序自动发起的,可能需要我们点击个按钮,或者切换个标签时才去请求数据。除了手动发起请求外,同样的可能还需要手动取消上一次的网络请求(如果未完成),那么 RxSwift 该如何实现呢?
  • 如下所示:
    • 每次点击“发起请求”按钮则去请求一次数据;
    • 如果请求没返回时,点击“取消请求”则可将其取消(取消后即使返回数据也不作处理)。
//“发起请求”按钮@IBOutlet weak var startBtn: UIButton!//“取消请求”按钮@IBOutlet weak var cancelBtn: UIButton!let disposeBag = DisposeBag()override func viewDidLoad() {super.viewDidLoad()//创建URL对象let urlString = "https://www.douban.com/j/app/radio/channels"let url = URL(string:urlString)//创建请求对象let request = URLRequest(url: url!)//发起请求按钮点击startBtn.rx.tap.asObservable().flatMap {URLSession.shared.rx.data(request: request).takeUntil(self.cancelBtn.rx.tap) //如果“取消按钮”点击则停止请求}.subscribe(onNext: {data inlet str = String(data: data, encoding: String.Encoding.utf8)print("请求成功!返回的数据是:", str ?? "")}, onError: { error inprint("请求失败!错误原因:", error)}).disposed(by: disposeBag)

三、将结果转为 Json 对象

  • 如果服务器返回的数据是 json 格式的话,可以使用 iOS 内置的 JSONSerialization 将其转成 JSON 对象,方便使用:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.data(request: request).subscribe(onNext: {data inlet json = try? (JSONSerialization.jsonObject(with: data, options: .allowFragments)as! [String: Any])print("--- 请求成功,返回的如下数据 ---")print(json!)
}).disposed(by: disposeBag)
  • 运行结果如下:
"https://www.douban.com/j/app/radio/channels" -i -v
Success (3410ms): Status 200
--- 请求成功!返回的如下数据 ---
["channels": <__NSArrayI 0x7ff0f2f07080>(
{"abbr_en" = "";"channel_id" = 9;name = "\U8f7b\U97f3\U4e50";"name_en" = "";"seq_id" = 8;
},
{"abbr_en" = "";"channel_id" = 10;name = "\U539f\U58f0";"name_en" = "";"seq_id" = 9;
},
{"abbr_en" = "";"channel_id" = 267;name = "Fly by midnight ";"name_en" = "";"seq_id" = 10;
},
{"abbr_en" = "";"channel_id" = 268;name = "\U72ec\U7acb";"name_en" = "";"seq_id" = 11;
},
{"abbr_en" = "";"channel_id" = 13;name = "\U7235\U58eb";"name_en" = "";"seq_id" = 12;
},
{"abbr_en" = "";"channel_id" = 14;name = "\U7535\U5b50";"name_en" = "";"seq_id" = 13;
},
{"abbr_en" = "";"channel_id" = 15;name = "\U8bf4\U5531";"name_en" = "";"seq_id" = 14;
},
{"abbr_en" = "";"channel_id" = 16;name = "R&B ";"name_en" = "";"seq_id" = 15;
},
{"abbr_en" = "";"channel_id" = 17;name = "\U65e5\U8bed";"name_en" = "";"seq_id" = 16;
},
{"abbr_en" = "";"channel_id" = 18;name = "\U97e9\U8bed";"name_en" = "";"seq_id" = 17;
},
{"abbr_en" = "";"channel_id" = 259;name = "\U6211\U7684\U5df4\U6bd4\U4f26\U604b\U4eba";"name_en" = "";"seq_id" = 18;
},
{"abbr_en" = "";"channel_id" = 20;name = "\U5973\U58f0";"name_en" = "";"seq_id" = 19;
},
{"abbr_en" = "";"channel_id" = 22;name = "\U6cd5\U8bed";"name_en" = "";"seq_id" = 20;
},
{"abbr_en" = "";"channel_id" = 151;name = "\U6237\U5916";"name_en" = "";"seq_id" = 21;
},
{"abbr_en" = "";"channel_id" = 152;name = "\U4f11\U606f";"name_en" = "";"seq_id" = 22;
},
{"abbr_en" = "";"channel_id" = 28;name = "\U52a8\U6f2b";"name_en" = "";"seq_id" = 26;
},
{"abbr_en" = "";"channel_id" = 32;name = "\U5496\U5561\U9986";"name_en" = "";"seq_id" = 27;
},
{"abbr_en" = "";"channel_id" = 155;name = "\U8212\U7f13";"name_en" = "";"seq_id" = 28;
},
{"abbr_en" = "";"channel_id" = 262;name = "18\U5c81\U9752\U6625\U7684\U53ec\U5524";"name_en" = "";"seq_id" = 29;
},
{"abbr_en" = "";"channel_id" = 41;name = "\U7ea2\U6b4c";"name_en" = "";"seq_id" = 30;
},
{"abbr_en" = "";"channel_id" = 170;name = "\U5723\U8bde";"name_en" = "";"seq_id" = 31;
},
{"abbr_en" = "";"channel_id" = 257;name = "\U8fd0\U52a8";"name_en" = "";"seq_id" = 32;
},
{"abbr_en" = "";"channel_id" = 264;name = "\U82f1\U8bed";"name_en" = "";"seq_id" = 33;
},
{"abbr_en" = "";"channel_id" = 179;name = "\U8c46\U74e3\U597d\U6b4c\U66f2";"name_en" = "";"seq_id" = 34;
}
)
]
  • 也可以在订阅前就进行转换:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.data(request: request).map {try JSONSerialization.jsonObject(with: $0, options: .allowFragments)as! [String: Any]}.subscribe(onNext: {data inprint("--- 请求成功!返回的如下数据 ---")print(data)}).disposed(by: disposeBag)
  • 还有更简单的方法,就是直接使用 RxSwift 提供的 rx.json 方法去获取数据,它会直接将结果转成 Json 对象:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.json(request: request).subscribe(onNext: {data inlet json = data as! [String: Any]print("--- 请求成功!返回的如下数据 ---")print(json )
}).disposed(by: disposeBag)
  • 将获取到的豆瓣频道列表数据转换成 Json 对象,并绑定到表格上显示:
// 创建表格视图
self.tableView = UITableView(frame: self.view.frame, style:.plain)
// 创建一个重用的单元格
self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView!)// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 获取列表数据
let data = URLSession.shared.rx.json(request: request).map{ result -> [[String: Any]] inif let data = result as? [String: Any],let channels = data["channels"] as? [[String: Any]] {return channels}else{return []}
}// 将数据绑定到表格
data.bind(to: tableView.rx.items) { (tableView, row, element) inlet cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!cell.textLabel?.text = "\(row):\(element["name"]!)"return cell
}.disposed(by: disposeBag)
  • 效果如下:

四、将结果映射成自定义对象

① 准备工作

  • 要实现数据到模型(model)的转换,首先需要引入一个第三方的数据模型转换框架:ObjectMapper。
  • 为了让 ObjectMapper 能够更好地与 RxSwift 配合使用,对 Observable 进行扩展(RxObjectMapper.swift),增加数据转模型对象、以及数据转模型对象数组这两个方法:
import ObjectMapper
import RxSwift// 数据映射错误
public enum RxObjectMapperError: Error {case parsingError
}// 扩展Observable:增加模型映射方法
public extension Observable where Element:Any {// 将Json数据转成对象public func mapObject< T>(type:T.Type) -> Observable<T> where T:Mappable {let mapper = Mapper<T>()return self.map { (element) -> T inguard let parsedElement = mapper.map(JSONObject: element) else {throw RxObjectMapperError.parsingError}return parsedElement}}// 将Json数据转成数组public func mapArray< T>(type:T.Type) -> Observable<[T]> where T:Mappable {let mapper = Mapper<T>()return self.map { (element) -> [T] inguard let parsedArray = mapper.mapArray(JSONObject: element) else {throw RxObjectMapperError.parsingError}return parsedArray}}
}

② 使用示例

  • 以豆瓣音乐频道数据为例,首先定义好相关模型(需要实现 ObjectMapper 的 Mappable 协议,并设置好成员对象与 Json 属性的相互映射关系):
// 豆瓣接口模型
class Douban: Mappable {// 频道列表var channels: [Channel]?init(){}required init?(map: Map) {}// Mappablefunc mapping(map: Map) {channels <- map["channels"]}
}// 频道模型
class Channel: Mappable {var name: String?var nameEn:String?var channelId: String?var seqId: Int?var abbrEn: String?init(){}required init?(map: Map) {}// Mappablefunc mapping(map: Map) {name <- map["name"]nameEn <- map["name_en"]channelId <- map["channel_id"]seqId <- map["seq_id"]abbrEn <- map["abbr_en"]}
}
  • 如下所示,获取数据,并转换成对应的模型:
// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 创建并发起请求
URLSession.shared.rx.json(request: request).mapObject(type: Douban.self).subscribe(onNext: { (douban: Douban) inif let channels = douban.channels {print("--- 共\(channels.count)个频道 ---")for channel in channels {if let name = channel.name, let channelId = channel.channelId {print("\(name) (id:\(channelId))")}}}}).disposed(by: disposeBag)
  • 如下所示,将数据换成模型,并绑定到表格上显示:
// 创建表格视图
self.tableView = UITableView(frame: self.view.frame, style:.plain)
// 创建一个重用的单元格
self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
self.view.addSubview(self.tableView!)// 创建URL对象
let urlString = "https://www.douban.com/j/app/radio/channels"
let url = URL(string:urlString)
// 创建请求对象
let request = URLRequest(url: url!)// 获取列表数据
let data = URLSession.shared.rx.json(request: request).mapObject(type: Douban.self).map{ $0.channels ?? []}// 将数据绑定到表格
data.bind(to: tableView.rx.items) { (tableView, row, element) inlet cell = tableView.dequeueReusableCell(withIdentifier: "Cell")!cell.textLabel?.text = "\(row):\(element.name!)"return cell
}.disposed(by: disposeBag)

RxSwift之深入解析URLSession的数据请求和数据处理相关推荐

  1. html 解析接口返回数据,请求第三方接口返回json格式数据的解析

    HttpClient httpClient = new HttpClient(); httpClient.getHttpConnectionManager().getParams().setConne ...

  2. 组装复杂json请求数据和解析复杂json数据

    在项目中有很多的接口对接的问题,于是就遇到了客户提供的各种奇葩的请求体.说一下最近遇到的一个复杂的json格式请求数据如下: {"bizData": {"userList ...

  3. AndroidStudio请求网络数据,把解析出来的数据放在listview里

    有网的效果图 无网效果图 MainActivity里面的代码 package com.qy.day02;import android.support.v7.app.AppCompatActivity; ...

  4. RxSwift之深入解析场景特征序列的使用和底层实现

    一.引序 任何序列都可以用 Observable 描述,创建序列 -> 订阅序列 -> 信号发送 -> 信号接收: Observable<Any>.create { (o ...

  5. iOS - NetRequest 网络数据请求

    1.网络请求 1.1 网络通讯三要素 1.IP 地址(主机名): 网络中设备的唯一标示.不易记忆,可以用主机名(域名). 1) IP V4: 0~255.0~255.0~255.0~255 ,共有 2 ...

  6. 关于HtmlAgilityPack解析页面中数据乱码问题

    第一种方式:      public static HtmlDocument LoadHtmlByUrls(string url)         {             HtmlDocument ...

  7. 使用 AFNetworking 进行 XML 和 JSON 数据请求

    (1)XML 数据请求 使用 AFNetworking 中的 AFHTTPRequestOperation 和 AFXMLParserResponseSerializer,另外结合第三方框架 XMLD ...

  8. 解析HTTP协议六种请求方法,get,head,put,delete,post有什么区别

    转载自  解析HTTP协议六种请求方法,get,head,put,delete,post有什么区别 标准Http协议支持六种请求方法,即: 1.GET 2.POST 3.PUT 4.Delete 5. ...

  9. android网络请求分析工具,android网络数据请求

    网络数据请求在android中应用很广泛,也很重要,所以我记录了上课讲的获取数据: 大家都知道,网络通信,发送请求有两种方式,GET和POST,这里也不例外. 1.HttpURLConnection的 ...

最新文章

  1. nginx实现http服务配置
  2. 小学五年级计算机二课活动记录,小学五年级主题班会的活动记录
  3. c ++递归算法数的计数_C ++程序使用数组中的递归查找数字的最后一次出现
  4. JavaScript | 声明数组并在每个循环中使用的代码
  5. 前端学习(172):格式化文本
  6. android主要文件的作用是什么,androidmanifest.xml文件的作用是什么
  7. Spring注解——使用@ComponentScan自动扫描组件
  8. Maven项目构建练习
  9. C++中未初始化的bool值的问题
  10. 通过names.index()方法找到第2个eva值 ,并将其改成EVA
  11. Facebook是如何大幅提升TLS连接效率的?
  12. ADVHAT: REAL-WORLD ADVERSARIAL ATTACK ON ARCFACE FACE ID SYSTEM 笔记
  13. rtmp协议官方规范
  14. python Pystaller 将python文件打包成exe
  15. 1.8 微信小程序 使用canvas绘制奥运会五环
  16. 第四周项目2--建立”单链表“算法库
  17. Causal Intervention for Weakly-Supervised Semantic Segmentation
  18. [Openstack]一键安装Openstack测试环境
  19. Java 学习 if循环 使用Scanner收集你的身高体重,并计算出你的BMI值是多少BMI的计算公式是 体重(kg) / (身高*身高)
  20. 性别识别_文字性别识别_语音性别识别 - 云+社区 - 腾讯云

热门文章

  1. 实例讲解如何通过Oracle成功发送邮件-入门基础
  2. Linux系统安全学习手册
  3. leetcode-139-单词拆分
  4. 061 hive中的三种join与数据倾斜
  5. C# BeginInvoke和EndInvoke方法
  6. 我的编程学习日志(1)--进制转换
  7. N!-201308071627.txt
  8. M2 Scrum 12.05
  9. 6-1 数组元素的区间删除
  10. C语言程序练习-L1-015 跟奥巴马一起画方块 (15分)