iOS網(wǎng)絡(luò)開發(fā)編程之NSURLConnection詳解

iOS網(wǎng)絡(luò)層常用的庫如ASIHTTPRequest,AFNetworking,MKNetworkKit等知名的第三方庫。隨著ASI不再更新许师,樓主基本上也跟著大部隊(duì)用了AF。AF用的是Cocoa層的API-NSURLConnection僚匆。

以前只是簡簡單單的用過NSURLConnection微渠,很多相關(guān)的方法都不是很熟悉,今天抽空了系統(tǒng)的學(xué)習(xí)了下咧擂,晚上順道總結(jié)下NSURLConnection的用法逞盆。

一、NSURLConnection的屬性及方法松申。

進(jìn)入NSURLConnection.h云芦,自上而下介紹所有的方法。

@interface NSURLConnection :

NSObject

{

@private

NSURLConnectionInternal *_internal;

}

/* Designated initializer */

/*

創(chuàng)建一個NSURLConnection贸桶,只建立連接舅逸,并沒有下載數(shù)據(jù)

request: 請求內(nèi)容

delegate:NSURLConnectionDelegate,NSURLConnection實(shí)例會強(qiáng)引用delegate皇筛,直到回調(diào)didFinishLoading,didFailWithError

NSURLConnection.cancel調(diào)用.(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 : 是否立即下載數(shù)據(jù),YES立即下載琉历,并把connection加入到當(dāng)前的runloop中。NO水醋,只建立連接旗笔,不下載數(shù)據(jù),需要手動

【connection start】開始下載數(shù)據(jù)拄踪。

*/

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

startImmediately:(BOOL)startImmediately

NS_AVAILABLE(10_5,

2_0);

/*

其實(shí)就是用的[self initWithRequest:request delegate:delegate startImmediately:YES];

不需要顯示的在去調(diào)用【connection start】

*/

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

/*

其實(shí)就是用的[self initWithRequest:request delegate:delegate startImmediately:YES];

不需要顯示的在去調(diào)用【connection start】

*/

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

/*

建立連接時用的請求

*/

@property (readonly,

copy) NSURLRequest *originalRequest

NS_AVAILABLE(10_8,

5_0);

/*

建立連接的請求進(jìn)過認(rèn)證協(xié)議可能會改變

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);

/*

開始下載數(shù)據(jù)蝇恶,通過- (instancetype)initWithRequest:(NSURLRequest

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

初始化的實(shí)例,調(diào)用【connection start】

*/

- (void)start

NS_AVAILABLE(10_5,

2_0);

/*

斷開網(wǎng)絡(luò)連接惶桐,取消請求撮弧,cancel方法不能保證代理回調(diào)立即不會調(diào)用(應(yīng)該是請求到的數(shù)據(jù),只能傳給代理)姚糊,cancel會release delegate

*/

- (void)cancel;

/*

將connection實(shí)例回調(diào)加入到一個runloop贿衍,NSURLConnectionDelegate回調(diào)會在這個runloop中響應(yīng)

注意該方法不能跟setDelegateQueue同時設(shè)置,只能選擇一個叛拷。

*/

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

NS_AVAILABLE(10_5,

2_0);

/*

取消在這個runloop中的回調(diào)

*/

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

NS_AVAILABLE(10_5,

2_0);

/*

如果設(shè)置了queue,回調(diào)將會在這個queue上進(jìn)行岂却,回調(diào)一次就類似與生成了一個NSBlockOperation加入到了queue中

注意該方法不能跟scheduleInRunLoop同時設(shè)置忿薇,只能選擇一個裙椭。

*/

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

@interface NSURLConnection (NSURLConnectionSynchronousLoading)

/*

類方法創(chuàng)建一個同步請求。這個方法是建立在異步的基礎(chǔ)上署浩,然后阻塞當(dāng)前線程實(shí)現(xiàn)的

response:響應(yīng)頭信息揉燃,傳遞一個二維指針

error:請求結(jié)果的狀態(tài)

*/

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

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

@end

@interface NSURLConnection (NSURLConnectionQueuedLoading)

/*

發(fā)起一個異步請求

queue:completionHandler會運(yùn)行在這個queue中

completionHandler:請求回調(diào)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類來實(shí)現(xiàn)NSURLConnectionDelegate弊攘,這樣其他地方在用到NSURLConnection的時候就不需要在寫一大堆協(xié)議了抢腐。

#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;

}

//廣播通知,執(zhí)行completionBlock

wkSelf.finished =

YES;

wkSelf.executing =

NO;

};

_connection = [[NSURLConnection

alloc] initWithRequest:self.request

delegate:delegate

//保持delegate強(qiáng)引用

startImmediately:NO];

//start前手動設(shè)置runloop為默認(rèn)

[_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被釋放襟交,強(qiáng)引用

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

//該方法只能簡單發(fā)起請求迈倍,等待結(jié)果,統(tǒng)計(jì)進(jìn)度不方便捣域。

[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回調(diào)在當(dāng)前operationqueue開辟的線程中完成

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

[connection

setDelegateQueue:self.queue];

[connection

start];

[self

printEnd];

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啼染,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子焕梅,更是在濱河造成了極大的恐慌迹鹅,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贞言,死亡現(xiàn)場離奇詭異斜棚,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蜗字,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門打肝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挪捕,你說我怎么就攤上這事粗梭。” “怎么了级零?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵断医,是天一觀的道長。 經(jīng)常有香客問我奏纪,道長鉴嗤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任序调,我火速辦了婚禮醉锅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘发绢。我一直安慰自己硬耍,他們只是感情好垄琐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著经柴,像睡著了一般狸窘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坯认,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天翻擒,我揣著相機(jī)與錄音,去河邊找鬼牛哺。 笑死陋气,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荆隘。 我是一名探鬼主播恩伺,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼椰拒!你這毒婦竟也來了晶渠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤燃观,失蹤者是張志新(化名)和其女友劉穎褒脯,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缆毁,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡番川,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了脊框。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颁督。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖浇雹,靈堂內(nèi)的尸體忽然破棺而出沉御,到底是詐尸還是另有隱情,我是刑警寧澤昭灵,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布吠裆,位于F島的核電站,受9級特大地震影響烂完,放射性物質(zhì)發(fā)生泄漏试疙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一抠蚣、第九天 我趴在偏房一處隱蔽的房頂上張望祝旷。 院中可真熱鬧,春花似錦、人聲如沸怀跛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敌完。三九已至,卻和暖如春羊初,著一層夾襖步出監(jiān)牢的瞬間滨溉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工长赞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晦攒,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓得哆,卻偏偏與公主長得像脯颜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子贩据,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容