NSURLConnection 实现webView显示HTTPS页面
最后更新于:2022-04-01 14:25:28
我们在浏览器访问https页面的时候的,会弹出:
![信任证书](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611039930e.jpg "")
我们接下来信任证书以及显示出来
遵循协议
~~~
@interface ViewController ()<NSURLConnectionDataDelegate>
~~~
interface:
~~~
@interface ViewController ()<NSURLConnectionDataDelegate>
/**
- 存储data数据
*/
@property(nonatomic,strong)NSMutableData *dataM;
/**
- 访问url链接
*/
@property(nonatomic,strong)NSURL *url;
@property(nonatomic,weak)IBOutlet UIWebView *webView;
@end
~~~
viewDidLoad:创建url以及发送请求
~~~
- (void)viewDidLoad {
[super viewDidLoad];
self.url = [NSURL URLWithString:@"https://mail.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
//发送请求
[NSURLConnection connectionWithRequest:request delegate:self];
}
~~~
实现代理方法:
~~~
#pragma mark - NSURLSessionDataDelegate代理方法
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler
{
NSLog(@"challenge = %@",challenge.protectionSpace.serverTrust);
//判断是否是信任服务器证书
if (challenge.protectionSpace.authenticationMethod ==NSURLAuthenticationMethodServerTrust)
{
//创建一个凭据对象
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
//告诉服务器客户端信任证书
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
}
}
/**
* 接收到服务器返回的数据时调用
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(@"接收到的数据%zd",data.length);
[self.dataM appendData:data];
}
/**
* 请求完毕
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *html = [[NSString alloc]initWithData:self.dataM encoding:NSUTF8StringEncoding];
NSLog(@"请求完毕");
[self.webView loadHTMLString:html baseURL:self.url];
}
~~~
懒加载:
~~~
- (NSMutableData *)dataM
{
if (_dataM == nil)
{
_dataM = [[NSMutableData alloc]init];
}
return _dataM;
}
~~~
至此,我们已经实现了https数据的展示:
**注意:**
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9843) 原因:没有信任服务器证书
在下面这个方法中:
~~~
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler()
~~~
我们通过protectionSpace.authenticationMethod判断是否信任服务器证书
- NSURLSessionAuthChallengeUseCredential = 0, 使用凭据 ,信任服务器证书
- NSURLSessionAuthChallengePerformDefaultHandling = 1, 默认处理,忽略服务器证书
- NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2, 整个请求被取消 凭据被忽略
- NSURLSessionAuthChallengeRejectProtectionSpace = 3, 本次拒绝,下次重试
一步一步 搞定RSA(公钥、私钥)
最后更新于:2022-04-01 14:25:26
首先我们要会生成RSA密钥文件,现在一步步的来给大家展示一下,如何生成我们所需的公钥和私钥文件:
**RSA密钥生成过程**
生成私钥文件
$ openssl genrsa -out private.pem 1024
openssl:是一个自由的软件组织,专注做加密和解密的框架。
genrsa:指定了生成了算法使用RSA
out:后面的参数表示生成的key的输入文件
1024:表示的是生成key的长度,单位字节(bits)
创建证书请求
$ openssl req -new -key private.pem -out rsacert.csr
可以拿着这个文件去数字证书颁发机构(即CA)申请一个数字证书。CA会给你一个新的文件cacert.pem,那才是你的数字证书。(要收费的)
生成证书并签名,有效期10年
$ openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
509是一种非常通用的证书格式。
将用上面生成的密钥privkey.pem和rsacert.csr证书请求文件生成一个数字证书rsacert.crt。这个就是公钥
转换格式 将 PEM 格式文件 转换成 DER 格式
$ openssl x509 -outform der -in rsacert.crt -out rsacert.der
在 iOS开发中,公钥是不能使用base64编码的,上面的命令是将公钥的base64编码字符串转换成二进制数据
导出 P12 文件
在iOS使用私钥不能直接使用,需要导出一个p12文件。下面命令就是将私钥文件导出为p12文件。
$ openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
执行完上面的这些,我们现在就得到了四个文件
![RSA](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611036d796.jpg "")
那么接下来,我们用这两个文件来使用一下(小点点的两个文件即可)。
~~~
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//创建加密对象
CryptorTools *tool = [[CryptorTools alloc]init];
//要加密的内容
NSString *msg = @"i love you";
//加载公钥
NSString *pubPath = [[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil];
[tool loadPublicKeyWithFilePath:pubPath];
//使用公钥加密
NSString *result = [tool RSAEncryptString:msg];
NSLog(@"加密 = %@",result);
//解密
//加载私钥
//密码是导出p12密码
NSString *privatePath = [[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil];
[tool loadPrivateKey:privatePath password:@"123456 "];
//使用私钥解密
NSString *result2 = [tool RSADecryptString:result];
NSLog(@"解密 = %@",result2);
}
~~~
看一下结果:
![RSA加密结果](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611037dfe9.jpg "")
搞定。
谈谈:服务器返回的数据,该怎么接收(int,NSNumber)
最后更新于:2022-04-01 14:25:23
其实很多时候,当服务器返回的是这种数据的时候:
![int NSNumbser](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_57061102ccbf2.jpg "")
那我们用int的来接收一下,看有没有问题:
![int](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_57061102e0b77.jpg "")
是不是一点问题都没有,那么用NSNumber 呢:
![NSNumber](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611030cc51.jpg "")
一样没有问题。但是关键的来了,若返回的是null .看一下:
![null](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_5706110327c2e.jpg "")
服务器返回什么,我们是决定不了的对吧,不能说,哎,你不能给我返回null。你看有人理你吗?
看一下int接收 有没有问题:
![崩溃](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611033849b.jpg "")
噢NO。崩了。
我们立马来看看NSNumber:
![NSNumber](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_5706110352c12.jpg "")
奇迹出来了。没有问题。所以呀,我们在处理这些问题的时候,要注意这点了。
这个控制器里面的代码,我们在[你可能不知道的事(服务器返回 id)](http://blog.csdn.net/yi_zz32/article/details/50065797) 这里有写。我就不写在这里了。
你可能不知道的事(服务器返回 id)
最后更新于:2022-04-01 14:25:21
首先说一下id的问题
加入服务器就是给我们反馈了一个id:如下:
![id](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_57061102a4860.jpg "")
既然返回的是id,有些人就乱了阵脚,“这个是关键字,怎么来接?”
其实没事,他返回什么给我们,我们就拿什么来接,就行。看一下如何解决:
既然返回的是字典,那么久字典转模型,写个模型先:
模型.h
~~~
@interface ZYDemo : NSObject
@property(nonatomic,assign)int id;
@property(nonatomic,copy)NSString *message;
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)demoWithDict:(NSDictionary *)dict;
@end
~~~
模型.m
~~~
@implementation ZYDemo
- (instancetype)initWithDict:(NSDictionary *)dict
{
if (self = [super init])
{
[self setValuesForKeysWithDictionary:dict];
}
return self;
}
+ (instancetype)demoWithDict:(NSDictionary *)dict
{
return [[self alloc]initWithDict:dict];
}
@end
~~~
在viewControllder进行数据解析
~~~
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL URLWithString:@"http://localhost/demo.json"];
NSURLRequest *request1 = [NSURLRequest requestWithURL:url];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:10.0];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
ZYDemo *demo = [ZYDemo demoWithDict:result];
NSLog(@"%@",demo);
}];
}
~~~
看一下我们的模型是否出来了:
![id](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_57061102b4fde.jpg "")
看,我们一样能解决,不要去为难服务器的人
解析XML
最后更新于:2022-04-01 14:25:19
由于我们搭建好了Apache服务器,那么我们接下来看一下如何解析服务器返回的xml文件
虽然开发中,服务器返回的xml格式的数据较少,但是偶尔还是会有的。
由于解析xml没有比较好的第三方框架,所以我们还是乖乖的苦逼的写代码,虽然说,代码没有难度
xml数据:
~~~
<videos>
<video videoId="1">
<name>张三</name>
<teacher>张老师</teacher>
</video>
</videos>
~~~
首先从服务器获取回来数据先
~~~
NSURL *url = [NSURL URLWithString:@"http://localhost/videos.xml"];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:1 timeoutInterval:10.0];
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc]init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
//创建xml解析器
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
//设置代理
parser.delegate = self;
//开始解析
[parser parse];
}];
~~~
我们依次的看一下我们要用到的代理方法
**开始解析调用(只会调用一次)**
~~~
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"1.开始文档");
}
~~~
**每发现一个开始节点就调用**
~~~
/**
* 每发现一个节点就调用
* * @param parser 解析器
* @param elementName 节点名字
* @param attributeDict 属性字典
*/
* (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(NSDictionary<NSString *, NSString *> *)attributeDict
{
NSLog(@"2.发现节点:%@",elementName);
if ([elementName isEqualToString:@"video"])
{
//创建模型对象
self.video = [[ZYVideo alloc]init];
}
[self.elementNameString setString:@""];
}
~~~
**发现节点内容**
~~~
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(@"3.发现节点内容:%@",string);
//把发现的内容进行拼接
[self.elementNameString appendString:string];
}
~~~
**发现结束节点**
~~~
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName
{
NSLog(@"3.发现结束节点 %@",elementName);
// NSLog(@"拼接的内容%@",self.elementNameString);
if ([elementName isEqualToString:@"name"])
{
self.video.name = self.elementNameString;
}else if ([elementName isEqualToString:@"teacher"])
{
self.video.teacher = self.elementNameString;
}
}
~~~
**解析完毕调用**
~~~
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
NSLog(@"解析完毕---------");
NSLog(@"%@",self.video);
}
~~~
提前做好的懒加载:
~~~
#pragma mark - 懒加载
- (NSMutableString *)elementNameString
{
if (_elementNameString == nil)
{
_elementNameString = [[NSMutableString alloc]init];
}
return _elementNameString;
}
~~~
搞定:看结果:
![解析XML](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_5706110286e08.jpg "")
图文讲解如何搭建Apache服务器
最后更新于:2022-04-01 14:25:17
如果我们能在本地搭建开发用的网络测试环境,能更有优势
步骤1:手动创建1个文件夹(文件夹名不限)
![步骤1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611023bbe5.jpg "")
步骤2:切换工作目录 cd /etc/apache2
![步骤2](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611024be0d.jpg "")
步骤3: 备份文件,以防不测,只需要执行一次就可以了
命令行代码:sudo cp httpd.conf httpd.conf.bak
步骤4:提示:如果后续操作出现错误!可以使用以下命令,恢复备份过的 httpd.conf 文件
命令行代码:sudo cp httpd.conf.bak httpd.conf
步骤5:vim里面只能用键盘,不能用鼠标 用vim编辑httpd.conf
命令行代码:sudo vim httpd.conf
步骤6:查找DocumentRoot
命令行代码:/DocumentRoot
将光标移动到首行 (按0)即可
进入编辑模式:(按 i)即可
修改下面的两个目录:
![步骤6](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611026219a.jpg "")
再修改这个地方:
![http](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611027192e.jpg "")
步骤7:ESC退出编辑
步骤8:查找php
命令行代码:/php
步骤9:删除行首注释,(按0到行首,按x 删除)
步骤10:wq 保存退出 (:q!)不保存退出
步骤11:切换工作目录
命令行:cd /etc
步骤12:拷贝php.ini文件
命令行: sudo cp php.ini.default php.ini
步骤13:重新启动apache服务器
命令行:sudo apachectl -k restart
大功告成:在浏览器输入:localhost 会有意想不到的结果。
然后我们把需要的文件 放到我们创建好的Sites,然后刷新浏览器 搞定。
解决Xcode 不能 访问http的问题
最后更新于:2022-04-01 14:25:14
由于Xcode默认不支持http的直接访问,那么我们就需要配置一下,我们先看一下没配置之前的Xcode返回的错误信息
![http不能访问](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_57061101c5965.jpg "")
发现错误信息,首先,不要慌张,现在出现错误,比到客户手上再出错,好得多。废话不多说,搞定他
步骤1:
![步骤1](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_57061101dba45.jpg "")
步骤2:
![步骤2](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_57061102053ee.jpg "")
步骤3:
~~~
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
~~~
插入这么一段代码,搞定。
可能这段代码,不任意记住但是没有必要记住,封装成一段代码,需要用的适合,输入关键字就出来了。看一下效果:
![效果](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611021e607.jpg "")
NSURLConnection 详解
最后更新于:2022-04-01 14:25:12
首先我们来创建一个URL
~~~
NSURL *url = [NSURL URLWithString:@"http://m.baidu.com"];
~~~
m:mobile专门给手机提供访问的连接
**创建请求对象,根据url向服务器索要数据**
~~~
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:15];
~~~
- 这个方法里面,我们要做的事情:
- 通过NSMutableURLRequest告诉服务器一些额外的信息
- timeoutInterval:请求超时时长,在指定的时间内,如果没有得到服务器的响应,则认为请求是失败的
- 默认是60s 但是建议在15~30s之间
- cachePolicy 缓存策略
- NSURLRequestUseProtocolCachePolicy = 0, 默认的策略
- NSURLRequestReloadIgnoringLocalCacheData = 1,每次从服务器加载,忽略本地缓存。
- 一般使用在实时性要求很高的应用,股票/12306/
- 下面两个一般使用在开发离线版应用。
- 离线版应用一般需要两个数据库,一个是本地数据库Sqlite3,一个服务器数据库。
- NSURLRequestReturnCacheDataElseLoad = 2, 有缓存,就返回缓存数据,没有就从服务器加载。
- NSURLRequestReturnCacheDataDontLoad = 3, 有缓存,就返回缓存数据,没有就不加载
- 告诉服务器,我是iPhone 并且支持Apple的网页套件
~~~
[request setValue:@"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_1) AppleWebKit/601.2.7 (KHTML, like Gecko) Version/9.0.1 Safari/601.2.7" forHTTPHeaderField:@"User-Agent"];
~~~
- 将请求对象发送给服务器–(网络访问都是耗时操作,使用异步)
- sendAsynchronousRequest:本身是异步,NSURLConnection内部会开启一条线程进行网络访问
- queue:决定了completionHandler回调所在的线程
- **如何选择队列**
- 如果获得服务器响应的时候,要做耗时操作,则选择自己创建队列,比如下载一个zip包,解压缩
- 如果获得响应后直接更新UI,则选择主队列。
completionHandler:服务器响应客户端的回调。
**response**
本质是NSHTTPURLResponse
- statusCode:状态码,可以根据这个值判断是否请求出错。
- allHeaderFields:获得响应体
- URL:一般使用在重定向,如果不需要重定向,响应的url和请求的url是一样的。
- MIMEType:服务器告诉客户端返回的数据类型,并决定客户端使用什么软件查看内容
-
textEncodingName : 服务器告诉客户端返回内容的编码格式
**下面两个属性一般使用在开发下载功能**
-
expectedContentLength:服务器返回数据的长度,客户端可以通过该属性获得文件大
- suggestedFilename:服务器建议客户端保存文件使用的名字
如下:
~~~
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
if(connectionError != nil || data.length == 0) {
NSLog(@"你的网络不给力哦");
return;
}
NSString *html = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
~~~
**加载html**
~~~
[self.webView loadData:data MIMEType:response.MIMEType textEncodingName:response.textEncodingName baseURL:url];
~~~
Socket的创建和连接
最后更新于:2022-04-01 14:25:10
从socket的创建开始说起(连接到京东。。。)
我们只要理解了各个参数,那么就学会了创建和连接
~~~
//连接到京东
- (void)connection{
if ([self connectionToHost:@"111.13.28.23" port:80]) {
// 发送数据
NSString *request = @"GET / HTTP/1.1\r\n"
"Host:m.jd.com\r\n"
"User-Agent:iPhone AppleWebKit\r\n"
"Connection:Close\r\n\r\n";
NSString *result = [self sendAndRecv:request];
NSLog(@"接收到的内容result = %@",result);
// 查找\r\n\r\n
NSRange range = [result rangeOfString:@"\r\n\r\n"];
if (range.location != NSNotFound) {
// 找到\r\n\r\n
NSString *html = [result substringFromIndex:range.location];
NSLog(@"接收到的内容html = %@",html);
[self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"http://m.jd.com"]];
}
}
}
~~~
**连接到服务器**
~~~
- (BOOL)connectionToHost:(NSString *)host port:(int)port{
// 创建客户端socket
/**
参数
domain: 协议域/协议族,AF_INET(IPV4的网络开发)
type: Socket 类型,SOCK_STREAM(TCP)/SOCK_DGRAM(UDP,报文)
protocol: IPPROTO_TCP,协议,如果输入0,可以根据第二个参数自动选择协议
返回值
socket,如果>0 就表示成功
*/
self.clientSocket = socket(AF_INET, SOCK_STREAM, 0);
// 建立连接
/**
参数
1> 客户端socket
2> 指向数据结构sockaddr的指针,其中包括目的端口和IP地址。即服务器的“结构体”地址
3> 结构体数据长度
返回值
0 成功/其他 错误代号,非0即真
*/
struct sockaddr_in socketServer;
// 1.协议---> 确定如何传输数据
socketServer.sin_family = AF_INET;
// 2.ip --> 通过ip找主机 inet_addr内部对字符串也进行了字节翻转(高低位互换)
socketServer.sin_addr.s_addr = inet_addr(host.UTF8String);
// 3.端口 ---> 通过端口找程序 htons:对整数进行高低位换号
socketServer.sin_port = htons(port);
return (connect(self.clientSocket, (const struct sockaddr *)&socketServer, sizeof(socketServer)) == 0);
}
~~~
**发送和接收**
~~~
- (NSString *)sendAndRecv:(NSString *)msg{
// 发送数据
/**
参数
1> 客户端socket
2> 发送内容地址 void * == id
3> 发送内容长度,是指字节的长度。
4> 发送方式标志,一般为0
返回值
如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR
*/
ssize_t sendLength = send(self.clientSocket, msg.UTF8String, strlen(msg.UTF8String), 0);
NSLog(@"发送了%ld字节,%zd--%zd",sendLength,msg.length,strlen(msg.UTF8String));
// 读取数据
/*
参数1:客户端的socket
参数2:接收内容的地址
参数3:接收内容的长度,告诉服务器一次只能接收多少字节的内容
参数4:接收方式标志,一般为0 表示阻塞式等待服务器响应
返回
— 接收的字节数
*/
uint8_t buffer[1024];
NSMutableData *dataM = [NSMutableData data];
ssize_t recvLength = -1;
while (recvLength != 0) {
recvLength = recv(self.clientSocket, buffer, sizeof(buffer), 0);
// 2000 80
NSLog(@"接收了%ld 字节",recvLength);
[dataM appendBytes:buffer length:recvLength];
}
NSString *resultStr = [[NSString alloc] initWithData:dataM encoding:NSUTF8StringEncoding];
return resultStr;
}
~~~
**断开连接**
~~~
- (void)disconnection{
// 断开连接
close(self.clientSocket);
}
~~~
其实也不难 对吧
**效果:**
![Socket](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-07_570611019701c.jpg "")
前言
最后更新于:2022-04-01 14:25:08
> 原文出处:[IOS 网络编程](http://blog.csdn.net/column/details/ios-data.html)
作者:[yi_zz32](http://blog.csdn.net/yi_zz32)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# IOS 网络编程
> IOS 网络编程 详细的讲解各种数据的解析