你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS網絡開發編程之NSURLConnection詳解

iOS網絡開發編程之NSURLConnection詳解

編輯:IOS開發綜合

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*) queue NS_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];


}



  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved