您的位置:首页 > 理论基础 > 计算机网络

网络请求与数据解析

2015-08-20 17:17 537 查看

同步、异步请求简介

同步请求会在当前线程中执行网络请求操作,一般情况是在主线程执行。

主线程默认处理用户交互信息,若执行网络请求,则在请求完成之前用户无法与界面交互



异步请求会新开辟一个线程,并在后台线程中执行请求操作。

后台线程与主线程操作同时执行,不会影响到主线程处理用户界面交互信息。



GET、POST请求方法

GET和POST方法是HTTP请求中的常用方法。

GET请求常用于向服务器请求数据资源、POST请求常用于向服务器提交或同步数据。

GET请求的参数会跟在URL后进行传递,请求的数据会附在URL之后,参数可能会被第三方拦截,存在不安全因素。

POST请求参数是拼接在请求报文中的,并且可以进行相应的加密机制,相比GET请求有更好的安全性。

NSURLConnection 简介

NSURLConnection是系统提供的一个网络请求类,可以实现HTTP请求中的GET及POST方法。

NSURLConnection也提供了包含同步、异步的请求方式。

NSURLConnection基于NSURLRequest发起一个请求。

NSURLRequest、NSURLConnection关系图:



NSURLRequest初始化:

// 1、便利构造初始化
+ (id)requestWithURL:(NSURL *)URL;

// 2、init初始化
- (id)initWithURL:(NSURL *)URL;


NSMutableURLRequest属性配置:

// 1、设置请求方式
- (void)setHTTPMethod:(NSString *)method;

// 2、设置头部参数
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field;

// 3、设置请求报文
- (void)setHTTPBody:(NSData *)data;


NSURLConnection同步请求实现:

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error;


NSURLConnection异步请求实现:

- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate;

+ (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate;


NSURLConnectionDelegate及NSURLConnectionDataDelegate提供了大量的接口来处理请求中的状态事件:

// 数据接受完
- (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、JSON数据格式解析

XML数据格式

XML(Extensive Markup Language):可扩展标记语言。

XML是网络通信中一种常用的数据交互格式,被设计用来传输和存储数据。

XML文档形成了一种树结构,它从“根部”开始,然后扩展到“枝叶”。





JSON数据格式

JSON(JavaScript Object Notation):JavaScript 对象表示法。

JSON 是存储和交换文本信息的语法,类似 XML。

JSON内部采用键值对的形式组合数据,类似于字典,不过JSON最外层也支持数组格式。

JSON 比 XML 更小、更快,更易解析。

JSON支持的数据类型包括数组、字符串、逻辑值、字典、Null等。



XML解析:

系统解析类:NSXMLParse

第三方库解析类:GDataXMLNode

GDataXMLDocument —- XML文档

GDataXMLNode —- 节点

GDataXMLElement —- 元素

解析方法:按层次获取元素或节点,然后调用方法获取到指定元素对应的值。

JSON解析:

系统解析类: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数据格式;

同步/异步 GET请求案例

效果展示



代码示例

#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请求案例

备注:程序中
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: