概述

NSURLConnection是负责发送请求,建立客户端与服务端的连接。发送数据给服务器,并收集来自服务器的响应数据。其中NSURLRequest类是用来封装一个请求,包含NSURL对象、请求方法、请求头、请求超时等信息。它有一个子类NSMutableURLRequest。

发送一个请求具体的步骤:

* 创建一个NSURL对象,设置请求路径

* 入NSURL创建的一个NSRULRequest对象,设置请求头、请求体。

* 使用NSURLConnection发送网络请求

NSURLConnection发送请求

发送同步请求

NSURLConnection类方法发送同步请求

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

第二个参数传入的响应头指针,真实的类型是NSHTTPURLResponse。返回值NSData为服务端响应体的数据。该函数是同步的(线程阻塞)。

发送异步请求

NSURLConnection类方法发送异步请求

+ (void)sendAsynchronousRequest:(NSURLRequest*) request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse* _Nullable response, NSData* _Nullable data, NSError* _Nullable connectionError)) handler

第二个参数queue决定方法的回调Block的线程。Block中的response真实类型为NSHTTPURLResponse是服务端响应的响应头信息,data为响应体。

代理方式发送异步请求

NSURLConnection也可以使用Delegate方式发送异步请求

NSURLConnection有三个方法设置代理发送异步请求

- (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate
+ (nullable NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate

这个两个方法底层会主动调用NSURLConnection的start方法发送请求,无须手动调用start方法。

- (nullable instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable id)delegate startImmediately:(BOOL)startImmediately

这个方法的startImmediately参数用户决定是否立即发送请求,如果传递为NO,我们需要拿到返回的NSURLConnection对象手动调用start方法发送请求。

通过代理方式发送异步请求,代理遵守协议并不是遵守NSURLConnectionDelegate 而是NSURLConnectionDataDelegate。NSURLConnectionDataDelegate协议遵守NSURLConnectionDelegate协议。

协议方法

// 接受到服务器的数据
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
// 接受到服务器的数据 如果数据量较大 该方法会多次被调用
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
// 请求完成
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
// 请求失败(比如请求超时 默认是60s)
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error

delegate异步请求适合服务端返回较大的数据场景。

POST请求

POST请求的的参数是放在请求体中,NSURLRequest默认是GET请求。因此需要它的子类NSMutableURLRequest创建一个可变的请求。

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520it&pwd=520it&type=JSON"]];

    // 设置POST请求 注意POST都为大写
request.HTTPMethod = @"POST";
// 设置请求出参数
request.HTTPBody = [@"username=coderhong&pwd=12345" dataUsingEncoding:NSUTF8StringEncoding];
// 设置请求超时(服务在超时时间内服务端还未返回数据 默认60s)
request.timeoutInterval = 10;
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) { NSLog(@"------%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];

其实完整的HTTP请求包含了请求头、请求体。使用NSURLConnection发送请求,默认帮我们设置了请求头信息。我们可以通过NSMutableURLRequest对象设置请求头、设置请求超时时间。

// 设置请求超时(服务在超时时间内服务端还未返回数据 默认60s)
request.timeoutInterval = 10; // 设置请求头
[request setValue:@"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" forHTTPHeaderField:@"User-Agent"];

URL包含中的解决方案

如果URL中包含了中文需要对URL中的中文进行转码。调用字符串的下面方法,生成转码后的URL字符串。如果是POST请求调用dataUsingEncoding:方法转成二进制内部已经进行了中文转码可以无需另外处理。

- (nullable NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)enc

NSURLConnection与runloop

NSURLConnection使用代理发送请求,默认代理方法是在主线程。我们可以通过NSURLConnection实例设置回调在子线程

// 发送请求
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
// 设置代理方法的执行线程
[conn setDelegateQueue: [[NSOperationQueue alloc] init]];

NSURLConnection发送请求后,一直在等待服务端一点一点的给它数据,所以应该有一个运行循环一直在等待服务器给它数据。也就是说NSURLConnection是在runloop接受服务器返回的数据的。其实NSURLConnection内部会关联当前线程的runloop。如果将发送的请求代码放在子线程中代理的方法不会执行,代码如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 发送请求
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
// 设置代理方法的执行线程
[conn setDelegateQueue: [[NSOperationQueue alloc] init]];
});

因为此时NSURLConnection关联当前的子线程runloop默认是没有开启的,因此需要手动开启子线程的runloop

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 发送请求
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
// 设置代理方法的执行线程
[conn setDelegateQueue: [[NSOperationQueue alloc] init]]; // 开启当前子线程的runloop
[[NSRunLoop currentRunLoop] run];
});

补充:如果我们想强制停止一个runloop需要CoreFoundation中函数。

void CFRunLoopStop(CFRunLoopRef rl);

注意:如果通过上面函数停止runloop,在开启runloop使用CFRunLoopRun()函数开启。不要使用[[NSRunLoop currentRunLoop] run];方式开启。

iOS开发系列-NSURLConnection的更多相关文章

  1. iOS开发系列--网络开发

    概览 大部分应用程序都或多或少会牵扯到网络开发,例如说新浪微博.微信等,这些应用本身可能采用iOS开发,但是所有的数据支撑都是基于后台网络服务器的.如今,网络编程越来越普遍,孤立的应用通常是没有生命力 ...

  2. iOS开发系列--Swift语言

    概述 Swift是苹果2014年推出的全新的编程语言,它继承了C语言.ObjC的特性,且克服了C语言的兼容性问题.Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在 ...

  3. iOS开发系列文章(持续更新……)

    iOS开发系列的文章,内容循序渐进,包含C语言.ObjC.iOS开发以及日后要写的游戏开发和Swift编程几部分内容.文章会持续更新,希望大家多多关注,如果文章对你有帮助请点赞支持,多谢! 为了方便大 ...

  4. iOS开发系列--App扩展开发

    概述 从iOS 8 开始Apple引入了扩展(Extension)用于增强系统应用服务和应用之间的交互.它的出现让自定义键盘.系统分享集成等这些依靠系统服务的开发变成了可能.WWDC 2016上众多更 ...

  5. iOS开发系列--Swift进阶

    概述 上一篇文章<iOS开发系列--Swift语言>中对Swift的语法特点以及它和C.ObjC等其他语言的用法区别进行了介绍.当然,这只是Swift的入门基础,但是仅仅了解这些对于使用S ...

  6. iOS开发系列--通知与消息机制

    概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地 ...

  7. iOS开发系列--数据存取

    概览 在iOS开发中数据存储的方式可以归纳为两类:一类是存储为文件,另一类是存储到数据库.例如前面IOS开发系列-Objective-C之Foundation框架的文章中提到归档.plist文件存储, ...

  8. iOS开发系列--C语言之基础知识

    概览 当前移动开发的趋势已经势不可挡,这个系列希望浅谈一下个人对IOS开发的一些见解,这个IOS系列计划从几个角度去说IOS开发: C语言 OC基础 IOS开发(iphone/ipad) Swift ...

  9. iOS开发系列--让你的应用“动”起来

    --iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌.在这里你可以看到iOS中如何使用图层精简非交互式绘图,如何通过核心动画创建 ...

随机推荐

  1. Android中的广播Broadcast详解

    今天来看一下Android中的广播机制,我们知道广播Broadcast是Android中的四大组件之一,可见他的重要性了,当然它的用途也很大的,比如一些系统的广播:电量低.开机.锁屏等一些操作都会发送 ...

  2. 移动Windows开始按钮到任务栏中的任何位置

    uses CommCtrl; procedure TForm1.Button1Click(Sender: TObject); var vHandle: THandle; vCount: Integer ...

  3. NX二次开发-UFUN获取点在面上的向量方向UF_MODL_ask_face_props【转载】

    1 NX11+VS2013 2 3 4 #include <uf.h> 5 #include <uf_ui.h> 6 #include <uf_modl.h> 7 ...

  4. 笨办法学Python记录--习题18 变量 函数 help的由来;if语句,循环和列表,冒泡排序,判断输入字符串的方法

    20140414 记录 习题17 - 33 函数可以做3件事: 1. 给代码片段命名,,就跟“变量”给字符串和数字命名一样. 2. 可以接受参数,就跟你的脚本接受argv 一样. 3. 通过使用#1 ...

  5. ionic:temple

    ylbtech-ionic:temple 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   作者:ylbtech出处:http://ylb ...

  6. 完美解决 IE6 position:fixed 固定定位问题

    关于 position:fixed; 属性 生成绝对定位的元素,相对于浏览器窗口进行定位. 元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定. pos ...

  7. 利用zk客户端删除solr shard

    进入zk客户端 ./bin/zkCli.sh -server ip:2181 显示所有的内容: ls / 删除数据: rmr /filename path

  8. 手动从零使用ELK构建一套搜索服务

    前言 这两天需要对接一个新的搜索业务,由于测试机器还没到位,所以就自己创造条件,通过在Windows上安装VM虚拟机,模拟整套环境,从而能快速进入核心业务的开发测试状态中. 系统环境安装配置 虚拟机V ...

  9. 2019-7-29-asp-dotnet-core-从-Frp-获取用户真实-IP-地址

    title author date CreateTime categories asp dotnet core 从 Frp 获取用户真实 IP 地址 lindexi 2019-07-29 08:28: ...

  10. Leetcode211. Add and Search Word - Data structure design 添加与搜索单词 - 数据结构设计

    设计一个支持以下两种操作的数据结构: void addWord(word) bool search(word) search(word) 可以搜索文字或正则表达式字符串,字符串只包含字母 . 或 a- ...