iOS网络开发编程之NSURLConnection详解 iOS网络层常用的库如ASIHTTPRequest,AFNetworking,MKNetworkKit等知名的第三方库。随着ASI不再更新,楼主

iOS网络开发编程之NSURLConnection详解

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

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

 

一、NSURLConnection的属性及方法。

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

 

@interface NSURLConnection : NSObject

{

@private

NSURLConnectionInternal *_internal;

}

 

/* Designated initializer */

/*

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

request: 请求内容

delegateNSURLConnectionDelegateNSURLConnection实例会强引用delegate,直到回调didFinishLoading,didFailWithErrorNSURLConnection.cancel调用.(During the download the connection maintains a strong reference to the

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

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

connection start】开始下载数据。

 

*/

-(instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegatestartImmediately:(BOOL)startImmediately NS_AVAILABLE(10_5, 2_0);

 

/*

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

 

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

 

*/

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

 

/*

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

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

*/

 

+(NSURLConnection*)connectionWithRequest:(NSURLRequest *)requestdelegate:(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 ofprotocol

canonicalization or due to followingredirects.

-currentRequest can be used to retrievethis value.

*/

 

@property (readonly, copy) NSURLRequest*currentRequest NS_AVAILABLE(10_8, 5_0);

 

/*

开始下载数据,通过-(instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegatestartImmediately:(BOOL)startImmediately 初始化的实例,调用【connection start

*/

- (void)start NS_AVAILABLE(10_5, 2_0);

/*

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

*/

- (void)cancel;

/*

connection实例回调加入到一个runloopNSURLConnectionDelegate回调会在这个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*) queue NS_AVAILABLE(10_7, 5_0);

 

 

 

@interface NSURLConnection(NSURLConnectionSynchronousLoading)

 

/*

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

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

error:请求结果的状态

*/

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

 

@end

 

 

@interface NSURLConnection(NSURLConnectionQueuedLoading)

 

/*

发起一个异步请求

queuecompletionHandler会运行在这个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 = [NSStringstringWithUTF8String:URLSTRING];

NSURL* url = [NSURLURLWithString:urlString];

NSURLRequest* request = [NSURLRequestrequestWithURL:url

cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData

timeoutInterval:30.f];

return request;

}

 

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

 

#import

 

typedefvoid(^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.ospropertyForKey:NSStreamDataWrittenToMemoryStreamKey]);

}

[self.os close];

 

_isFinish = YES;

}

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

if ([responsezisKindOfClass:[NSHTTPURLResponse class]]) {

NSHTTPURLResponse* hr =(NSHTTPURLResponse*)responsez;

if (hr.statusCode == 200) {

_contentLength = hr.expectedContentLength;

// _os = [NSOutputStreamoutputStreamToFileAtPath:[NSHomeDirectory()stringByAppendingPathComponent:@"Documents/image.jpg"] append:NO];

_os = [NSOutputStreamoutputStreamToMemory];

 

[_os open];

}

}

}

 

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

if (self.completionBlock) {

NSError* error = [NSErrorerrorWithDomain: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 = [NSMutableDatadataWithCapacity: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 -1if an error occurs. More information about the error can be obtained withstreamError. If the receiver is a fixed-length stream and has reached itscapacity, 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:[NSRunLoopcurrentRunLoop] 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{

[selfwillChangeValueForKey:@"isFinished"];

_finished = finished;

[self didChangeValueForKey:@"isFinished"];

 

}

- (void)setExecuting:(BOOL)executing{

[selfwillChangeValueForKey:@"isExecuting"];

_executing = executing;

[selfdidChangeValueForKey:@"isExecuting"];

}

- (BOOL)isConcurrent{

return YES;

}

 

 

 

@end

 

 

 

 

 

 

同步请求:

 

-(IBAction)sync:(id)sender{

[self printGO];

 

//

NSURLResponse* response = nil;

NSError* error = nil;

NSData* data = [NSURLConnectionsendSynchronousRequest:[self request]

returningResponse:&response

error:&error];

 

NSLog(@"get sync data!");

if ([responseisKindOfClass:[NSHTTPURLResponse class]]) {

NSHTTPURLResponse* hr =(NSHTTPURLResponse*)response;

if (hr.statusCode == 200) {

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

self.imageView.image = [UIImageimageWithData: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 = [UIImageimageWithData:sOp.buffer];

});

};

[operation start];

[self printEnd];

}

 

 

异步请求:

 

-(IBAction)async:(id)sender{

 

[self printGO];

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

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

[NSURLConnectionsendAsynchronousRequest:[self request]

queue:self.queue //completionHandler run onthis queue

completionHandler:^(NSURLResponse*response, NSData *data, NSError *connectionError) {

if ([responseisKindOfClass:[NSHTTPURLResponse class]]) {

NSHTTPURLResponse* hr =(NSHTTPURLResponse*)response;

if (hr.statusCode == 200) {

[self printCurrentThread];

self.imageView.image = [UIImageimageWithData:data];

}

}

}];

 

 

[self printEnd];

 

 

}

 

 

-(IBAction)async:(id)sender{

 

[self printGO];

NSURLConnectionDelegate* connectionDelegate= [NSURLConnectionDelegate new];

connectionDelegate.completionBlock = ^(iddata){

[self printCurrentThread];

if ([data isKindOfClass:[NSData class]]) {

[[NSOperationQueue mainQueue]addOperationWithBlock:^{

self.imageView.image = [UIImageimageWithData:data];

 

}];

}

};

 

 

NSURLConnection* connection =[[NSURLConnection alloc] initWithRequest:[self request]delegate:connectionDelegate];

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

// [connection scheduleInRunLoop:[NSRunLoopcurrentRunLoop] forMode:NSDefaultRunLoopMode];

[connection setDelegateQueue:self.queue];

[connection start];

 

[self printEnd];

 

 

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值