同步请求会在当前线程中执行网络请求操作,一般情况是在主线程执行。
主线程默认处理用户交互信息,若执行网络请求,则在请求完成之前用户无法与界面交互
异步请求会新开辟一个线程,并在后台线程中执行请求操作。
后台线程与主线程操作同时执行,不会影响到主线程处理用户界面交互信息。
GET和POST方法是HTTP请求中的常用方法。
GET请求常用于向服务器请求数据资源、POST请求常用于向服务器提交或同步数据。
GET请求的参数会跟在URL后进行传递,请求的数据会附在URL之后,参数可能会被第三方拦截,存在不安全因素。
POST请求参数是拼接在请求报文中的,并且可以进行相应的加密机制,相比GET请求有更好的安全性。
NSURLConnection是系统提供的一个网络请求类,可以实现HTTP请求中的GET及POST方法。
NSURLConnection也提供了包含同步、异步的请求方式。
NSURLConnection基于NSURLRequest发起一个请求。
NSURLRequest、NSURLConnection关系图:
// 1、便利构造初始化
+ (id)requestWithURL:(NSURL *)URL;
// 2、init初始化
- (id)initWithURL:(NSURL *)URL;
// 1、设置请求方式
- (void)setHTTPMethod:(NSString *)method;
// 2、设置头部参数
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field;
// 3、设置请求报文
- (void)setHTTPBody:(NSData *)data;
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate; + (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate;
// 数据接受完
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
// 接收到数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
// 请求数据失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
XML(Extensive Markup Language):可扩展标记语言。
XML是网络通信中一种常用的数据交互格式,被设计用来传输和存储数据。
XML文档形成了一种树结构,它从“根部”开始,然后扩展到“枝叶”。
JSON(JavaScript Object Notation):JavaScript 对象表示法。
JSON 是存储和交换文本信息的语法,类似 XML。
JSON内部采用键值对的形式组合数据,类似于字典,不过JSON最外层也支持数组格式。
JSON 比 XML 更小、更快,更易解析。
JSON支持的数据类型包括数组、字符串、逻辑值、字典、Null等。
系统解析类:NSXMLParse
第三方库解析类:GDataXMLNode
解析方法:按层次获取元素或节点,然后调用方法获取到指定元素对应的值。
系统解析类:NSJSONSerialization
第三方库解析类:SBJSON、JSONKit 等。
解析方法:在JSON字符串以及JSON对象之间直接进行转化。
使用NSJSONSerialization:
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
tips:本案例中主要解析JSON数据格式;
#import "ViewController.h"
// get net:http://apistore.baidu.com/apiworks/servicedetail/112.html
// ------------------------ defines
#define NSLOG(OBJECT) NSLog(@"%@", OBJECT)
#define Get_Url_Apikey @"159d95a8c050074fe3ca0df0d901fc62"
#define Get_Url_String @"http://apis.baidu.com/apistore/weatherservice/weather?citypinyin=chengdu"
// ------------------------ identifier
static NSString *const kUITableViewCellIdentifierGet = @"cellIdentifierGet"; /**< 表格视图标识符Get */
// ------------------------ titles
static NSString *const WD = @"风向";
static NSString *const WS = @"风力";
static NSString *const city = @"城市";
static NSString *const cityPinYin = @"城市拼音";
static NSString *const date = @"日期";
static NSString *const fbTime = @"发布时间";
static NSString *const temp = @"当前气温";
static NSString *const h_temp = @"最高气温";
static NSString *const l_temp = @"最低气温";
static NSString *const latitude = @"纬度";
static NSString *const longitude = @"经度";
static NSString *const weather = @"天气";
@interface ViewController () <UITableViewDelegate, UITableViewDataSource, NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
NSArray *_getRequestDataTitles; /**< Get请求界面标题 */
NSArray *_getRequestDataKeys; /**< Get请求数据Key */
NSMutableData *_revicedData; /**< 存储接收到的data数据 */
NSMutableArray *_dataSource; /**< 数据源 */
}
@property (nonatomic, strong) UITableView *tableView; /**< 表格视图 */
- (void)initializeUserInterface; /**< 初始化用户界面 */
- (void)initializeDataSource; /**< 初始化数据源 */
- (NSMutableURLRequest *)createGetRequest; /**< 创建Get请求 */
- (void)sendSynchronousGetRequet; /**< 发送同步Get请求 */
- (void)sendAsynchronousGetRequest; /**< 发送异步Get请求 */
- (void)analyticalDataOfGetRequestWithData:(NSData *)data; /**< Get请求数据解析 */
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeDataSource];
[self initializeUserInterface];
// 1、发送同步GET请求
// [self sendSynchronousGetRequet];
// 2、发送异步GET请求
[self sendAsynchronousGetRequest];
}
#pragma mark- init
- (void)initializeDataSource {
// 初始化数据源
_dataSource = [NSMutableArray array];
// 初始化数据
_revicedData = [NSMutableData data];
// get数据请求标题
_getRequestDataTitles = @[city,cityPinYin,temp,h_temp,l_temp,weather,longitude,latitude,date,fbTime,WD,WS];
// get数据请求数据key
_getRequestDataKeys = @[@"city",@"pinyin",@"temp",@"h_tmp",@"l_tmp",@"weather",@"longitude",@"latitude",@"date",@"time",@"WD",@"WS"];
}
- (void)initializeUserInterface {
// 关闭系统自动调整滚动视图偏移
self.automaticallyAdjustsScrollViewInsets = NO;
// 添加表格视图
[self.view addSubview:self.tableView];
}
#pragma mark - request methods
// 创建请求
- (NSMutableURLRequest *)createGetRequest {
// 创建请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:Get_Url_String ]];
// 配置header(ApiKey)
[request addValue:Get_Url_Apikey forHTTPHeaderField:@"apikey"];
return request;
}
// 发送同步GET请求
- (void)sendSynchronousGetRequet {
// 创建请求
NSMutableURLRequest *request = [self createGetRequest];
// 创建错误信息
NSError *error = nil;
// 发起同步Get请求
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
// 判断是否请求成功
if (error) {
NSLOG(error.localizedDescription);
}else{
[self analyticalDataOfGetRequestWithData:data];
}
}
// 发送异步GET请求
- (void)sendAsynchronousGetRequest {
// 创建请求
NSMutableURLRequest *requst = [self createGetRequest];
// 发送请求
// 1、需遵守<NSURLConnectionDelegate, NSURLConnectionDataDelegate>;
// 2、在代理方法中处理请求回调信息;
// 3、协议方法:
// didFailWithError:请求失败处理->打印失败信息
// didReceiveData:数据接收处理->拼接数据
// connectionDidFinishLoading:数据接收完毕处理->解析数据
[NSURLConnection connectionWithRequest:requst delegate:self];
}
#pragma mark - analytical methods
// 解析数据
- (void)analyticalDataOfGetRequestWithData:(NSData *)data {
NSError *error = nil;
id object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
// 判断是否解析成功
if (error) {
NSLOG(error.localizedDescription);
}else{
// 移除数据源
[_dataSource removeAllObjects];
NSDictionary *dict = object[@"retData"];
for (int i = 0; i < _getRequestDataKeys.count; i++) {
// 获取数据
id value = [dict objectForKey:_getRequestDataKeys[i]];
// 判断数据是否为NSNumber类型,如果是,则转成字符串类型
if ([value isKindOfClass:[NSNumber class]]) {
value = [NSString stringWithFormat:@"%@", value];
}
// 创建字典存储数据
NSDictionary *dataDict = @{_getRequestDataTitles[i] : value};
// 将字典数据存入数据源中
[_dataSource addObject:dataDict];
}
[_tableView reloadData];
}
}
#pragma mark - private methods
// 处理网络请求参数
- (NSData *)httpBodyWithParametersDict:(NSMutableDictionary *)parametersDict {
// 初始化空字符串
NSMutableString *string = [NSMutableString string];
// for-in循环遍历字典数据
for (NSString *key in parametersDict) {
// 拼接参数
[string appendFormat:@"%@=%@&", key, parametersDict[key]];
}
// 截取参数多余字符并通过NSUTF8StringEncoding转码为NSData数据类型
return [[string substringToIndex:string.length - 1] dataUsingEncoding:NSUTF8StringEncoding];
}
#pragma mark - <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
// 请求失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLOG(error.localizedDescription);
}
// 接收到数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 拼接数据
[_revicedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 解析数据
[self analyticalDataOfGetRequestWithData:_revicedData];
}
#pragma mark - UITableViewDataSource methods
// 设置行
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// 设置组
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _dataSource.count;
}
// 设置单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// 表格视图重用机制
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kUITableViewCellIdentifierGet];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:kUITableViewCellIdentifierGet];
}
// 设置表格无选中样式
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// 单元格赋值
cell.textLabel.text = ((NSDictionary *)_dataSource[indexPath.row]).allKeys[0];
cell.detailTextLabel.text = [_dataSource[indexPath.row] objectForKey:_getRequestDataTitles[indexPath.row]];
return cell;
}
#pragma mark - getter
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - 64) style:UITableViewStylePlain];
// 设置代理
_tableView.delegate = self;
// 设置数据源
_tableView.dataSource = self;
// 设置尾部视图清除分割线
_tableView.tableFooterView = [UIView new];
}
return _tableView;
}
@end
备注:程序中Post_Url_Apikey
需要自行在聚合数据中注册账号申请;
#import "ViewController.h"
// post net:http://www.juhe.cn/docs/api/id/46/aid/131
// ------------------------ defines
#define NSLOG(OBJECT) NSLog(@"%@", OBJECT)
#define Post_Url_Apikey @"请输入自己的key"
#define Post_Url_String @"http://apis.juhe.cn/cook/queryid"
#define Post_Url_Parameter_Id @(1001)
#define Post_Url_Parameter_Dtype @"json"
// ------------------------ identifier
static NSString *const kUITableViewCellIdentifierPost = @"cellIdentifierPost"; /**< 表格视图标识符Post */
@interface ViewController () <UITableViewDelegate, UITableViewDataSource, NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
NSMutableData *_revicedData; /**< 存储接收到的data数据 */
NSMutableArray *_dataSource; /**< 数据源 */
}
@property (nonatomic, strong) UITableView *tableView; /**< 表格视图 */
- (void)initializeUserInterface; /**< 初始化用户界面 */
- (void)initializeDataSource; /**< 初始化数据源 */
- (NSMutableURLRequest *)createPostRequest; /**< 创建Post请求 */
- (void)sendSynchronousPostRequet; /**< 发送同步Post请求 */
- (void)sendAsynchronousPostRequest; /**< 发送异步Post请求 */
- (void)analyticalDataOfPostRequestWithData:(NSData *)data; /**< Post请求数据解析 */
- (NSData *)httpBodyWithParametersDict:(NSMutableDictionary *)parametersDict; /**< 构造请求参数 */
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initializeDataSource];
[self initializeUserInterface];
// 1、发送同步POST请求
[self sendSynchronousPostRequet];
// 2、发送异步POST请求
// [self sendAsynchronousPostRequest];
}
#pragma mark- init
- (void)initializeDataSource {
// 初始化数据源
_dataSource = [NSMutableArray array];
// 初始化数据
_revicedData = [NSMutableData data];
}
- (void)initializeUserInterface {
// 关闭系统自动调整滚动视图偏移
self.automaticallyAdjustsScrollViewInsets = NO;
// 添加表格视图
[self.view addSubview:self.tableView];
}
#pragma mark - request methods
- (NSMutableURLRequest *)createPostRequest {
// 创建请求
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:Post_Url_String]];
// 配置请求
request.timeoutInterval = 10;
request.HTTPMethod = @"POST";
// 构造请求参数
NSMutableDictionary *parametersDict = [NSMutableDictionary dictionary];
[parametersDict setObject:Post_Url_Parameter_Id forKey:@"id"];
[parametersDict setObject:Post_Url_Parameter_Dtype forKey:@"dtype"];
[parametersDict setObject:Post_Url_Apikey forKey:@"key"];
//
NSData *parametersData = [self httpBodyWithParametersDict:parametersDict];
// 设置请求报文
request.HTTPBody = parametersData;
return request;
}
- (void)sendSynchronousPostRequet {
// 创建查询请求
NSMutableURLRequest *request = [self createPostRequest];
// 发送请求
NSError *error = nil;
id object = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if (error) {
NSLOG(error.localizedDescription);
}else{
// 解析数据
[self analyticalDataOfPostRequestWithData:object];
}
}
- (void)sendAsynchronousPostRequest {
// 创建请求
NSMutableURLRequest *request = [self createPostRequest];
// 发送请求
// 1、需遵守<NSURLConnectionDelegate, NSURLConnectionDataDelegate>;
// 2、在代理方法中处理请求回调信息;
// 3、协议方法:
// didFailWithError:请求失败处理->打印失败信息
// didReceiveData:数据接收处理->拼接数据
// connectionDidFinishLoading:数据接收完毕处理->解析数据
[NSURLConnection connectionWithRequest:request delegate:self];
}
#pragma mark - analytical methods
// 解析数据
- (void)analyticalDataOfPostRequestWithData:(NSData *)data {
NSError *error = nil;
// JSON数据解析
id object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
if (error) {
NSLOG(error.localizedDescription);
}else{
[_dataSource removeAllObjects];
[_dataSource addObjectsFromArray:(NSArray *)object[@"result"][@"data"][0][@"steps"]];
[_tableView reloadData];
}
}
#pragma mark - private methods
// 处理网络请求参数
- (NSData *)httpBodyWithParametersDict:(NSMutableDictionary *)parametersDict {
// 初始化空字符串
NSMutableString *string = [NSMutableString string];
// for-in循环遍历字典数据
for (NSString *key in parametersDict) {
// 拼接参数
[string appendFormat:@"%@=%@&", key, parametersDict[key]];
}
// 截取参数多余字符并通过NSUTF8StringEncoding转码为NSData数据类型
return [[string substringToIndex:string.length - 1] dataUsingEncoding:NSUTF8StringEncoding];
}
#pragma mark - <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
// 请求失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLOG(error.localizedDescription);
}
// 接收到数据
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 拼接数据
[_revicedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// 解析数据
[self analyticalDataOfPostRequestWithData:_revicedData];
}
#pragma mark - UITableViewDataSource methods
// 设置行
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// 设置组
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _dataSource.count;
}
// 设置单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// 表格视图重用机制
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kUITableViewCellIdentifierPost];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:kUITableViewCellIdentifierPost];
}
// 设置表格无选中样式
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// 单元格赋值
cell.detailTextLabel.text = @"";
cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:_dataSource[indexPath.row][@"img"]]]];
cell.textLabel.text = _dataSource[indexPath.row][@"step"];
return cell;
}
#pragma mark - getter
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - 64) style:UITableViewStylePlain];
// 设置代理
_tableView.delegate = self;
// 设置数据源
_tableView.dataSource = self;
// 设置尾部视图清除分割线
_tableView.tableFooterView = [UIView new];
}
return _tableView;
}
@end