美文网首页
iOS网络开发编程之NSURLConnection详解

iOS网络开发编程之NSURLConnection详解

作者: Zd_silent | 来源:发表于2016-01-26 16:00 被阅读446次

    iOS网络层常用的库如ASIHTTPRequest,AFNetworking,MKNetworkKit等知名的第三方库。随着ASI不再更新,楼主基本上也跟着大部队用了AF。AF用的是Cocoa层的API-NSURLConnection。

    以前只是简简单单的用过NSURLConnection,很多相关的方法都不是很熟悉,今天抽空了系统的学习了下,晚上顺道总结下NSURLConnection的用法。

    一、NSURLConnection的属性及方法。

    进入NSURLConnection.h,自上而下介绍所有的方法。

    @interface NSURLConnection :

    NSObject

    {

    @private

    NSURLConnectionInternal *_internal;

    }

    /* Designated initializer */

    /*

    创建一个NSURLConnection,只建立连接,并没有下载数据

    request: 请求内容

    delegate:NSURLConnectionDelegate,NSURLConnection实例会强引用delegate,直到回调didFinishLoading,didFailWithError

    NSURLConnection.cancel调用.(During the download the connection maintains a strong reference

    to the

    delegate. It releases that strong reference when the connection finishes loading, fails, or is canceled)

    startImmediately : 是否立即下载数据,YES立即下载,并把connection加入到当前的runloop中。NO,只建立连接,不下载数据,需要手动

    【connection start】开始下载数据。

    */

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

    startImmediately:(BOOL)startImmediately

    NS_AVAILABLE(10_5,

    2_0);

    /*

    其实就是用的[self initWithRequest:request delegate:delegate startImmediately:YES];

    不需要显示的在去调用【connection start】

    */

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

    /*

    其实就是用的[self initWithRequest:request delegate:delegate startImmediately:YES];

    不需要显示的在去调用【connection start】

    */

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

    /*

    建立连接时用的请求

    */

    @property (readonly,

    copy) NSURLRequest *originalRequest

    NS_AVAILABLE(10_8,

    5_0);

    /*

    建立连接的请求进过认证协议可能会改变

    As the connection performs the load,

    this request may change as a result of protocol

    canonicalization or due to following redirects.

    -currentRequest can be used to retrieve this value.

    */

    @property (readonly,

    copy) NSURLRequest *currentRequest

    NS_AVAILABLE(10_8,

    5_0);

    /*

    开始下载数据,通过- (instancetype)initWithRequest:(NSURLRequest

    *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately

    初始化的实例,调用【connection start】

    */

    - (void)start

    NS_AVAILABLE(10_5,

    2_0);

    /*

    断开网络连接,取消请求,cancel方法不能保证代理回调立即不会调用(应该是请求到的数据,只能传给代理),cancel会release delegate

    */

    - (void)cancel;

    /*

    将connection实例回调加入到一个runloop,NSURLConnectionDelegate回调会在这个runloop中响应

    注意该方法不能跟setDelegateQueue同时设置,只能选择一个。

    */

    - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode

    NS_AVAILABLE(10_5,

    2_0);

    /*

    取消在这个runloop中的回调

    */

    - (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode

    NS_AVAILABLE(10_5,

    2_0);

    /*

    如果设置了queue,回调将会在这个queue上进行,回调一次就类似与生成了一个NSBlockOperation加入到了queue中

    注意该方法不能跟scheduleInRunLoop同时设置,只能选择一个。

    */

    - (void)setDelegateQueue:(NSOperationQueue*) queueNS_AVAILABLE(10_7,5_0);

    @interface NSURLConnection (NSURLConnectionSynchronousLoading)

    /*

    类方法创建一个同步请求。这个方法是建立在异步的基础上,然后阻塞当前线程实现的

    response:响应头信息,传递一个二维指针

    error:请求结果的状态

    */

    + (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse

    **)response error:(NSError **)error;

    @end

    @interface NSURLConnection (NSURLConnectionQueuedLoading)

    /*

    发起一个异步请求

    queue:completionHandler会运行在这个queue中

    completionHandler:请求回调block

    */

    + (void)sendAsynchronousRequest:(NSURLRequest*) request

    queue:(NSOperationQueue*) queue

    completionHandler:(void (^)(NSURLResponse* response,

    NSData* data, NSError* connectionError)) handler

    NS_AVAILABLE(10_7,

    5_0);

    @end

    二、NSURLConnection用法

    上边方法介绍的差不多了,写几个小demo试试。

    首先定义一些基本配置

    static char *

    const URLSTRING =

    "http://f.hiphotos.baidu.com/image/h%3D200/sign=a1217b1330fa828bce239ae3cd1f41cd/0e2442a7d933c895cc5c676dd21373f082020081.jpg";

    -(NSURLRequest*)request{

    NSString* urlString = [NSString

    stringWithUTF8String:URLSTRING];

    NSURL* url = [NSURL

    URLWithString:urlString];

    NSURLRequest* request = [NSURLRequest

    requestWithURL:url

    cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData

    timeoutInterval:30.f];

    return request;

    }

    另外,抽象出来了一个NSURLConnectionDelegate类来实现NSURLConnectionDelegate,这样其他地方在用到NSURLConnection的时候就不需要在写一大堆协议了。

    #import

    typedef

    void(^NSURLConnectionCompeletionBlock)(id);

    @interface NSURLConnectionDelegate :NSObject

    @property(nonatomic ,

    strong , readonly)

    NSOutputStream* os;

    @property(nonatomic ,

    assign , readonly)

    BOOL isFinish;

    @property(nonatomic ,

    strong , readonly)

    NSMutableData* buffer;

    @property(nonatomic ,

    assign , readonly)

    NSUInteger contentLength;

    @property(nonatomic ,

    strong)

    NSURLConnectionCompeletionBlock completionBlock;

    @end

    #import "NSURLConnectionDelegate.h"

    @implementation NSURLConnectionDelegate

    - (void)dealloc

    {

    NSLog(@"__%s__",__FUNCTION__);

    }

    - (void)connectionDidFinishLoading:(NSURLConnection *)connection{

    if (self.completionBlock) {

    self.completionBlock([self.os

    propertyForKey:NSStreamDataWrittenToMemoryStreamKey]);

    }

    [self.os

    close];

    _isFinish =

    YES;

    }

    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse

    *)responsez{

    if ([responsez isKindOfClass:[NSHTTPURLResponse

    class]]) {

    NSHTTPURLResponse* hr = (NSHTTPURLResponse*)responsez;

    if (hr.statusCode ==

    200) {

    _contentLength = hr.expectedContentLength;

    //            _os = [NSOutputStream

    outputStreamToFileAtPath:[NSHomeDirectory()

    stringByAppendingPathComponent:@"Documents/image.jpg"] append:NO];

    _os = [NSOutputStream

    outputStreamToMemory];

    [_os

    open];

    }

    }

    }

    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError

    *)error{

    if (self.completionBlock) {

    NSError* error = [NSError

    errorWithDomain:error.domain

    code:error.code

    userInfo:error.userInfo];

    self.completionBlock(error);

    }

    _isFinish =

    YES;

    [self.os

    close];

    }

    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData

    *)data{

    if (!self.buffer) {

    _buffer = [NSMutableData

    dataWithCapacity:self.contentLength];

    }

    [self.buffer

    appendData:data];

    //

    NSUInteger totalLength = data.length;

    NSUInteger totalWirte =

    0;

    const uint8_t * datas = data.bytes;

    while (totalWirte < totalLength) {

    /*

    The number of bytes actually written, or -1 if an error occurs.

    More information about the error can be obtained with streamError. If

    the receiver is a fixed-length stream and has reached its capacity, 0 is

    returned.

    */

    NSInteger writeLength = [self.os

    write:&datas[totalWirte]

    maxLength:(totalLength - totalWirte)];

    if (writeLength == -1) {

    [connection

    cancel];

    break;

    }

    totalWirte += writeLength;

    NSLog(@"totalLenght = %lu , totalWirte = %lu",totalLength,totalWirte);

    }

    }

    配合写个NSOperation

    #import

    @interface NSURLConnectionOperation :

    NSOperation

    @property(nonatomic ,

    strong) NSURLRequest* request;

    @property(nonatomic ,

    strong ) NSData* buffer;

    -(instancetype)initWithRequest:(NSURLRequest*)request;

    -(void)startAsync;

    @end

    #import "NSURLConnectionOperation.h"

    #import "NSURLConnectionDelegate.h"

    @interface

    NSURLConnectionOperation ()

    @property (nonatomic,

    assign, getter=isExecuting)

    BOOL executing;

    @property (nonatomic,

    assign, getter=isFinished)

    BOOL finished;

    @property (nonatomic,

    assign, getter=isConcurrent)

    BOOL concurrent;

    @property(nonatomic ,

    strong ) NSThread* thread;

    @property(nonatomic ,

    strong  ) NSURLConnection* connection;

    @end

    @implementation NSURLConnectionOperation

    @synthesize executing=_executing,finished=_finished,concurrent=_concurrent;

    - (void)dealloc

    {

    NSLog(@"%s",__FUNCTION__);

    }

    -(instancetype)initWithRequest:(NSURLRequest *)request{

    self = [super

    init];

    if (self) {

    self.request = request;

    }

    return

    self;

    }

    - (void)start{

    if (!self.thread) {

    _thread = [NSThread

    currentThread];

    }

    self.finished =

    NO;

    self.executing =

    YES;

    __weak

    NSURLConnectionOperation* wkSelf = self;

    NSURLConnectionDelegate* delegate = [NSURLConnectionDelegate

    new];

    delegate.completionBlock = ^(id data){

    if (!wkSelf.buffer) {

    wkSelf.buffer = data;

    }

    //广播通知,执行completionBlock

    wkSelf.finished =

    YES;

    wkSelf.executing =

    NO;

    };

    _connection = [[NSURLConnection

    alloc] initWithRequest:self.request

    delegate:delegate

    //保持delegate强引用

    startImmediately:NO];

    //start前手动设置runloop为默认

    [_connection

    scheduleInRunLoop:[NSRunLoop

    currentRunLoop] forMode:NSDefaultRunLoopMode];

    [_connection

    start];

    while (!self.isFinished) {

    [[NSRunLoop

    currentRunLoop] runMode:NSDefaultRunLoopMode

    beforeDate:[NSDate

    distantFuture]];

    }

    NSLog(@"start end!!");

    }

    - (void)startAsync{

    _thread = [[NSThread

    alloc] initWithTarget:self

    selector:@selector(start)

    object:nil];

    [self.thread

    start];

    }

    - (void)setFinished:(BOOL)finished{

    [self

    willChangeValueForKey:@"isFinished"];

    _finished = finished;

    [self

    didChangeValueForKey:@"isFinished"];

    }

    - (void)setExecuting:(BOOL)executing{

    [self

    willChangeValueForKey:@"isExecuting"];

    _executing = executing;

    [self

    didChangeValueForKey:@"isExecuting"];

    }

    - (BOOL)isConcurrent{

    return

    YES;

    }

    @end

    同步请求:

    -(IBAction)sync:(id)sender{

    [self

    printGO];

    //

    NSURLResponse* response =

    nil;

    NSError* error = nil;

    NSData* data = [NSURLConnection

    sendSynchronousRequest:[self

    request]

    returningResponse:&response

    error:&error];

    NSLog(@"get sync data!");

    if ([response isKindOfClass:[NSHTTPURLResponse

    class]]) {

    NSHTTPURLResponse* hr = (NSHTTPURLResponse*)response;

    if (hr.statusCode ==

    200) {

    NSLog(@"sync repsonse head: \n%@",hr.allHeaderFields);

    self.imageView.image = [UIImage

    imageWithData:data];

    }

    }

    [self

    printEnd];

    }

    -(IBAction)sync:(id)sender{

    [self

    printGO];

    NSURLConnectionOperation* operation = [[NSURLConnectionOperation

    alloc]

    initWithRequest:[self

    request]];

    __weak NSURLConnectionOperation* wkOp = operation;

    operation.completionBlock = ^{

    __strong

    NSURLConnectionOperation* sOp = wkOp;//防止wkOp被释放,强引用

    NSLog(@"set ?");

    dispatch_async(dispatch_get_main_queue(), ^{

    self.imageView.image = [UIImage

    imageWithData:sOp.buffer];

    });

    };

    [operation

    start];

    [self

    printEnd];

    }

    异步请求:

    -(IBAction)async:(id)sender{

    [self

    printGO];

    //*************************** NSURLConnection async

    //该方法只能简单发起请求,等待结果,统计进度不方便。

    [NSURLConnection

    sendAsynchronousRequest:[self

    request]

    queue:self.queue

    //completionHandler run on  this queue

    completionHandler:^(NSURLResponse *response,

    NSData *data, NSError *connectionError) {

    if ([response isKindOfClass:[NSHTTPURLResponse

    class]]) {

    NSHTTPURLResponse* hr = (NSHTTPURLResponse*)response;

    if (hr.statusCode ==

    200) {

    [self

    printCurrentThread];

    self.imageView.image = [UIImage

    imageWithData:data];

    }

    }

    }];

    [self

    printEnd];

    }

    -(IBAction)async:(id)sender{

    [self

    printGO];

    NSURLConnectionDelegate* connectionDelegate = [NSURLConnectionDelegate

    new];

    connectionDelegate.completionBlock = ^(id data){

    [self

    printCurrentThread];

    if ([data isKindOfClass:[NSData

    class]]) {

    [[NSOperationQueue

    mainQueue] addOperationWithBlock:^{

    self.imageView.image = [UIImage

    imageWithData:data];

    }];

    }

    };

    NSURLConnection* connection = [[NSURLConnection

    alloc] initWithRequest:[self

    request] delegate:connectionDelegate];

    //delegate回调在当前operationqueue开辟的线程中完成

    //    [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

    [connection

    setDelegateQueue:self.queue];

    [connection

    start];

    [self

    printEnd];

    }

    相关文章

      网友评论

          本文标题:iOS网络开发编程之NSURLConnection详解

          本文链接:https://www.haomeiwen.com/subject/uyddkttx.html