您的位置:首页 > 移动开发 > IOS开发

iOS-Network学习笔记(二)——NSURLConnection

2016-06-01 21:43 525 查看
1. NSURLConnection简介


(1)构造函数和调度函数

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

该方法是NSURLConnection的默认构造函数,startImmediately参数,如果为YES,代表会将当前的connection实例加入到当前的runloop中,该connection的delegate的回调方法都会在当前线程执行,自动实现调度,所以这种情况下甚至是不需要调用 -start方法来开始请求;如果为NO,则需要手动调度,将当前的connection加入到一个线程的runloop中(如果不添加,默认会添加到当前线程的runloop中)。

- (nullable

instancetype)initWithRequest:(NSURLRequest *)request delegate:(nullable

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

上述的实例构造函数和类构造的本质是一样的,最终会调用到默认构造函数,startImmediately参数为YES。

NSURLConnection的执行必须是在一个开启runloop的线程中的,如果执行线程没有开启runloop,connection在start之后,可能会收不到回调方法。PS:主线程的runloop默认是开启的。
在某些开源的网络框架中,开始一个connection的时候,都会开启当前线程的runloop,比如AFNetworking中,所有的网络请求都是在一个特定的线程中执行,这个线程在初始化的时候就开启一个runloop。
+ (void)networkRequestThreadEntryPoint:(id)__unused
object {

   
@autoreleasepool
{

        [[NSThread

currentThread]

setName:@"AFNetworking"];

       
NSRunLoop
*runLoop = [NSRunLoop

currentRunLoop];

        [runLoop
addPort:[NSMachPort

port]

forMode:NSDefaultRunLoopMode];

        [runLoop
run];

    }

}

+ (NSThread
*)networkRequestThread {

   
static
NSThread
*_networkRequestThread =
nil;

   
static
dispatch_once_t
oncePredicate;

   
dispatch_once(&oncePredicate, ^{

        _networkRequestThread = [[NSThread

alloc]

initWithTarget:self

selector:@selector(networkRequestThreadEntryPoint:)

object:nil];

        [_networkRequestThread
start];

    });

   
return
_networkRequestThread;

}

SDWebImage框架中,没有特定某个线程来执行connection,而是让operat
da34
ionqueue来分配线程执行,所以在connection start的时候,会开启当前线程的runloop

if
(floor(NSFoundationVersionNumber)
<=
NSFoundationVersionNumber_iOS_5_1) {

           
CFRunLoopRunInMode(kCFRunLoopDefaultMode,

10,

false);

        }

       
else {

           
CFRunLoopRun();

        }

手动调度函数有下面三个,前两个是设置/取消connection 回调方法所在的runloop中,第三个直接设置一个operationQueue,将connection的delegate的回调方法交给 queue来调度

- (void)scheduleInRunLoop:(NSRunLoop
*)aRunLoop forMode:(NSRunLoopMode)mode NS_AVAILABLE(10_5,

2_0);

- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSRunLoopMode)mode NS_AVAILABLE(10_5,

2_0);

- (void)setDelegateQueue:(nullable
NSOperationQueue*) queue NS_AVAILABLE(10_7,

5_0);

(2)start和cancel

        start的方法调用时机,是NSURLConnection创建时startImmediately为NO的时候,要手动调用;cancel方法,提供给我们一个手动结束这个网络连接。-cancel方法,是理论上终止这个网络连接,但是也有可能不起任何作用,deleagte回调方法还会继续;但是如果确定被cancel,delegate就会被释放。

(3)canHandleRequest方法
     
         这个方法,是判断能否通过一个request实例化一个connection。处理方式,是判断这个request能否被请求,正式发送之前的例行检查。

(4)两个category
 
        两个category提供了两个类方法,同步加载以及异步加载,简单处理结果(block回调的形式)。代码如下,第一个是同步加载,会阻塞当前线程;第二个是异步加载,同时会有一个回调block,处理成功的data或者是失败的error
+ (nullable
NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse *

__nullable
*
__nullable)response error:(NSError **)error
+ (void)sendAsynchronousRequest:(NSURLRequest*)
request

                          queue:(NSOperationQueue*) queue
              completionHandler:(void
(^)(NSURLResponse*
__nullable response, NSData*
__nullable
data, NSError*
__nullable connectionError)) handler

2.  NSURLConnection Delegate

(1)NSURLConnectionDelegate
- (void)connection:(NSURLConnection
*)connection didFailWithError:(NSError *)error;

- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection;
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge
*)challenge;
如上代码:第一个方法是在connection发生error后进行的回调,(最多回调一次),只要进行回调之后,delegate之后就不会再有回调的方法;第二个是询问connection实例要不要CredentialStorage,不管返回是Y/N,都三个回调都会进行调用的;都三个是connection连接需要进行认证相关的操作回调

(2)NSURLConnectionDataDelegate
- (nullable
NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(nullable
NSURLResponse *)response;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse
*)response;
- (void)connection:(NSURLConnection
*)connection didReceiveData:(NSData *)data;
- (nullable
NSInputStream *)connection:(NSURLConnection *)connection needNewBodyStream:(NSURLRequest *)request;

- (void)connection:(NSURLConnection *)connection   didSendBodyData:(NSInteger)bytesWritten

                                                 totalBytesWritten:(NSInteger)totalBytesWritten
                                         totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite;
- (nullable
NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
如上代码:该delegate是将网络数据存储在内存中的回调。第一个方法,是在需要改变request(重定向)的时候,返回一个request来进行继续加载,当然也可以返回nil(connection就会被终止,delegate回调会继续直到finish/error,一般情况下是error);第二个方法,是在收到服务器的响应时进行调用的;第三个方法,是获得网络数据的回调(可能多次调用);第四个方法,是在需要给request增加一些请求body的情况下进行调用的(连接错误或者认证错误),返回nil将会cancel这个connection;第五个方法,是在上传过程中,提供的process回调,(可以计算百分比);第六个方法,是要不要将这个connection的response缓存起来,下次调用可以直接从缓存拿(返回nil,就不能拿;如果进行缓存了,request的参数设置成可以从缓存拿,才会拿着个缓存);最后一个方法,是connection完成的回调。

(3)NSURLConnectionDownloadDelegate
- (void)connection:(NSURLConnection
*)connection didWriteData:(long

long)bytesWritten totalBytesWritten:(long

long)totalBytesWritten expectedTotalBytes:(long

long) expectedTotalBytes;
- (void)connectionDidResumeDownloading:(NSURLConnection *)connection
totalBytesWritten:(long
long)totalBytesWritten expectedTotalBytes:(long
long) expectedTotalBytes;
- (void)connectionDidFinishDownloading:(NSURLConnection
*)connection destinationURL:(NSURL *) destinationURL;
如上代码:该delegate是将网络数据存储在文件中的回调。第一个方法,是获取当前写到文件中的进度;第二个方法是获取断点续传的进度;最后一个方法是必须要实现的,连接结束,提供了暂时存储文件的临时URL,我们需要的是将这个文件的数据转移(如果需要),之后这个临时文件就会被释放。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息