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];
}
网友评论