您的位置:首页 > 理论基础 > 计算机网络

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

2015-08-19 21:32 357 查看
iOS网络开发编程之NSURLConnection详解

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,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方法不能保证代理回调立即不会调用(应该是请求到的数据,只能传给代理),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*) 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)

/*
发起一个异步请求
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 = [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];

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