大家都知道ASIHTTPRequest系列的類很好用,功能很強大。但也像NSURLConnection一樣,一個網絡請求就需要實例化一個對象,而且無法避免重復請求的問題。
我個人不習慣用ASIHTTPRequest,因為它功能太強大了,函數太多了,而我們平時的項目僅僅是處理基於HTTP協議的網絡交互,用ASIHTTPRequest未免太“奢侈”了。更重要的是,它並無法避免網絡的重復請求的問題,而且無法控制網絡請求數量,所以僅僅使用ASIHTTPRequest還不夠。
事實上,用NSURLConnection足夠了。下面是我寫的封裝
HTTPConnection.h
1. <span style="font-size:16px;">//
2. // HTTPConnection.h
3. //
4. //
5. // Created by Jianhong Yang on 12-1-3.
6. // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7. //
8.
9. #import <Foundation/Foundation.h>
10.
11.
12. #define MAXNUMBER_HTTPCONNECTION 30
13.
14. @protocol HTTPConnectionDelegate;
15.
16. @interface HTTPConnection : NSObject {
17. @private
18. //
19. int _numberOfHTTPConnection;
20. NSMutableArray *_marrayTaskDic;
21.
22. id <HTTPConnectionDelegate> _delegate;
23. }
24.
25. @property (nonatomic, assign) id <HTTPConnectionDelegate> delegate;
26.
27. // 根據URL獲取Web數據
28. // dicParam
29. // type:int,請求類型
30. - (BOOL)requestWebDataWithURL:(NSString *)strURL andParam:(NSDictionary *)dicParam;
31.
32. // 根據URLRequest獲取Web數據
33. // dicParam
34. // type:int,請求類型
35. - (BOOL)requestWebDataWithRequest:(NSURLRequest *)request andParam:(NSDictionary *)dicParam;
36.
37. //取消網絡請求
38. - (BOOL)cancelRequest:(NSDictionary *)dicParam;
39.
40. //清空網絡請求
41. - (void)clearRequest;
42.
43. @end
44.
45.
46. @protocol HTTPConnectionDelegate <NSObject>
47.
48. @optional
49.
50. // 網絡數據下載失敗
51. - (void)httpConnect:(HTTPConnection *)httpConnect error:(NSError *)error with:(NSDictionary *)dicParam;
52.
53. // 服務器返回的HTTP信息頭
54. - (void)httpConnect:(HTTPConnection *)httpConnect receiveResponseWithStatusCode:(NSInteger)statusCode
55. andAllHeaderFields:(NSDictionary *)dicAllHeaderFields with:(NSDictionary *)dicParam;
56.
57. // 服務器返回的部分數據
58. - (void)httpConnect:(HTTPConnection *)httpConnect receiveData:(NSData *)data with:(NSDictionary *)dicParam;
59.
60. // 網絡數據下載完成
61. - (void)httpConnect:(HTTPConnection *)httpConnect finish:(NSData *)data with:(NSDictionary *)dicParam;
62.
63. @end
64.
65.
66. #ifdef DEBUG
67.
68. #define HTTPLOG(fmt,...) NSLog((@"HTTP->%s(%d):"fmt),__PRETTY_FUNCTION__,__LINE__,##__VA_ARGS__)
69.
70. #else
71.
72. #define HTTPLOG(fmt,...) NSLog(fmt,##__VA_ARGS__)
73.
74. #endif</span>
HTTPConnection.m
[plain] view plaincopy
1. //
2. // HTTPConnection.m
3. //
4. //
5. // Created by Jianhong Yang on 12-1-3.
6. // Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
7. //
8.
9. #import "HTTPConnection.h"
10.
11.
12. @interface HTTPConnection (Private)
13. - (void)startHTTPConnection;
14. @end
15.
16.
17. @implementation HTTPConnection
18.
19. @synthesize delegate = _delegate;
20.
21. - (id)init
22. {
23. self = [super init];
24. if (self) {
25. // Custom initialization.
26. _numberOfHTTPConnection = 0;
27. _marrayTaskDic = [[NSMutableArray alloc] initWithCapacity:5];
28. }
29. return self;
30. }
31.
32. - (void)dealloc
33. {
34. //清空任務
35. [self clearRequest];
36. //
37. [_marrayTaskDic release];
38.
39. [super dealloc];
40. }
41.
42.
43. #pragma mark -
44. #pragma mark Public
45.
46. // 根據URL獲取Web數據
47. // dicParam
48. // type:int,請求類型
49. - (BOOL)requestWebDataWithURL:(NSString *)strURL andParam:(NSDictionary *)dicParam
50. {
51. if (nil == dicParam) {
52. return NO;
53. }
54.
55. NSURL *url = [NSURL URLWithString:strURL];
56. NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
57. BOOL success = [self requestWebDataWithRequest:request andParam:dicParam];
58. [request release];
59. return success;
60. }
61.
62. // 根據URLRequest獲取Web數據
63. // dicParam
64. // type:int,請求類型
65. - (BOOL)requestWebDataWithRequest:(NSURLRequest *)request andParam:(NSDictionary *)dicParam
66. {
67. if (nil == dicParam) {
68. return NO;
69. }
70. //請求類型必須存在
71. if (nil == [dicParam objectForKey:@"type"]) {
72. HTTPLOG(@"任務參數不足");
73. return NO;
74. }
75. //正在處理或等待處理的任務不再接收
76. for (NSDictionary *dicTask in _marrayTaskDic) {
77. //
78. if ([dicParam isEqualToDictionary:[dicTask objectForKey:@"param"]]) {
79. HTTPLOG(@"任務重復:%@", dicParam);
80. return NO;
81. }
82. }
83.
84. HTTPLOG(@"添加新任務,參數:%@", dicParam);
85. NSMutableDictionary *mdicTask = [[NSMutableDictionary alloc] initWithCapacity:3];
86. //設置數據緩存
87. NSMutableData *mdataCache = [[NSMutableData alloc] init];
88. [mdicTask setObject:mdataCache forKey:@"cache"];
89. [mdataCache release];
90. //參數
91. [mdicTask setObject:dicParam forKey:@"param"];
92. //創建HTTP網絡連接
93. NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
94. [mdicTask setObject:urlConnection forKey:@"connect"];
95. [urlConnection release];
96. //保存到數組
97. [_marrayTaskDic addObject:mdicTask];
98. [mdicTask release];
99.
100. [self startHTTPConnection];
101. return YES;
102. }
103.
104. //取消網絡請求
105. - (BOOL)cancelRequest:(NSDictionary *)dicParam
106. {
107. if (nil == dicParam) {
108. return NO;
109. }
110. //遍歷所有任務
111. for (int i = 0; i < _marrayTaskDic.count; i++) {
112. //查看任務是否相同
113. NSDictionary *dicTask = [_marrayTaskDic objectAtIndex:i];
114. if ([dicParam isEqualToDictionary:[dicTask objectForKey:@"param"]]) {
115. //取消網絡請求
116. NSURLConnection *connect = [dicTask objectForKey:@"connect"];
117. [connect cancel];
118. //從任務隊列中刪除
119. [_marrayTaskDic removeObjectAtIndex:i];
120. _numberOfHTTPConnection -= 1;
121. return YES;
122. }
123. }
124. return NO;
125. }
126.
127. //清空網絡請求
128. - (void)clearRequest
129. {
130. //遍歷所有任務
131. for (NSDictionary *dicTask in _marrayTaskDic) {
132. NSURLConnection *connect = [dicTask objectForKey:@"connect"];
133. [connect cancel];
134. //
135. _numberOfHTTPConnection -= 1;
136. }
137. //從任務隊列中刪除
138. [_marrayTaskDic removeAllObjects];
139. }
140.
141.
142. #pragma mark -
143. #pragma mark NSURLConnectionDataDelegate
144.
145. - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
146. {
147. HTTPLOG(@"網絡請求錯誤:%@", error);
148. //
149. NSDictionary *dicTask = nil;
150. for (int i = 0; i < _marrayTaskDic.count; i++) {
151. NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
152. //找到網絡連接相應的數據字典
153. if ([dic objectForKey:@"connect"] == connection) {
154. dicTask = dic;
155. break;
156. }
157. }
158.
159. //
160. if (dicTask) {
161. [dicTask retain];
162. //刪除
163. [_marrayTaskDic removeObject:dicTask];
164. NSDictionary *dicParam = [dicTask objectForKey:@"param"];
165. if ([_delegate respondsToSelector:@selector(httpConnect:error:with:)]) {
166. [_delegate httpConnect:self error:error with:dicParam];
167. }
168. [dicTask release];
169. _numberOfHTTPConnection -= 1;
170. }
171.
172. //
173. [self startHTTPConnection];
174. }
175.
176. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
177. {
178. HTTPLOG(@"網絡請求收到響應");
179. //
180. NSDictionary *dicTask = nil;
181. for (int i = 0; i < _marrayTaskDic.count; i++) {
182. NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
183. //找到網絡連接相應的數據字典
184. if ([dic objectForKey:@"connect"] == connection) {
185. dicTask = dic;
186. break;
187. }
188. }
189. //
190. if ([response isMemberOfClass:NSHTTPURLResponse.class]) {
191. NSHTTPURLResponse *responseHTTP = (NSHTTPURLResponse *)response;
192. NSUInteger statusCode = responseHTTP.statusCode;
193. NSDictionary *dicAllHeaderFields = responseHTTP.allHeaderFields;
194. NSDictionary *dicParam = [dicTask objectForKey:@"param"];
195. //收到服務器返回的HTTP信息頭
196. SEL receiveResponse = @selector(httpConnect:receiveResponseWithStatusCode:andAllHeaderFields:with:);
197. if ([self.delegate respondsToSelector:receiveResponse]) {
198. [self.delegate httpConnect:self receiveResponseWithStatusCode:statusCode
199. andAllHeaderFields:dicAllHeaderFields with:dicParam];
200. }
201. }
202. }
203.
204. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
205. {
206. HTTPLOG(@"網絡請求收到數據");
207. //
208. NSDictionary *dicTask = nil;
209. for (int i = 0; i < _marrayTaskDic.count; i++) {
210. NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
211. //找到網絡連接相應的數據字典
212. if ([dic objectForKey:@"connect"] == connection) {
213. dicTask = dic;
214. break;
215. }
216. }
217.
218. //
219. if (dicTask) {
220. //向緩存中添加數據
221. NSMutableData *mdataCache = [dicTask objectForKey:@"cache"];
222. [mdataCache appendData:data];
223. NSDictionary *dicParam = [dicTask objectForKey:@"param"];
224. HTTPLOG(@"該數據的參數:%@", dicParam);
225. //收到部分數據
226. if ([self.delegate respondsToSelector:@selector(httpConnect:receiveData:with:)]) {
227. [self.delegate httpConnect:self receiveData:data with:dicParam];
228. }
229. }
230. HTTPLOG(@"網絡請求收到數據並處理完成");
231. }
232.
233. - (void)connectionDidFinishLoading:(NSURLConnection *)connection
234. {
235. HTTPLOG(@"網絡請求結束");
236. //
237. NSDictionary *dicTask = nil;
238. for (int i = 0; i < _marrayTaskDic.count; i++) {
239. NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
240. //找到網絡連接相應的數據字典
241. if ([dic objectForKey:@"connect"] == connection) {
242. dicTask = dic;
243. break;
244. }
245. }
246.
247. //
248. if (dicTask) {
249. [dicTask retain];
250. //刪除
251. [_marrayTaskDic removeObject:dicTask];
252. NSData *dataCache = [dicTask objectForKey:@"cache"];
253. NSDictionary *dicParam = [dicTask objectForKey:@"param"];
254. if ([_delegate respondsToSelector:@selector(httpConnect:finish:with:)]) {
255. [_delegate httpConnect:self finish:dataCache with:dicParam];
256. }
257. [dicTask release];
258. _numberOfHTTPConnection -= 1;
259. }
260.
261. [self startHTTPConnection];
262. }
263.
264.
265. #pragma mark - Private
266.
267. - (void)startHTTPConnection
268. {
269. if (_numberOfHTTPConnection < MAXNUMBER_HTTPCONNECTION) {
270. if (_numberOfHTTPConnection < _marrayTaskDic.count) {
271. NSDictionary *dicTask = [_marrayTaskDic objectAtIndex:_numberOfHTTPConnection];
272. NSURLConnection *urlConnection = [dicTask objectForKey:@"connect"];
273. [urlConnection start];
274. //
275. _numberOfHTTPConnection += 1;
276. }
277. }
278. HTTPLOG(@"正在處理的網絡請求數:%i,等待處理的網絡請求:%i",
279. _numberOfHTTPConnection, _marrayTaskDic.count-_numberOfHTTPConnection);
280. }
281.
282. @end www.2cto.com
這個類有四個接口,後兩個是取消網絡請求的,不必討論。前兩個是發起網絡請求的,用的最多的就是這兩個接口了。如果只是通過GET方法從服務器取數據,第一個接口足夠了。當然也可以用第二個。如果需要用POST方式向服務器發送數據,得用第二個接口。
第一個接口的第一個參數是URL字符串,第二個參數用來區分網絡請求的,如果兩次請求的第二個參數一樣,第二次請求會被過濾掉。這個參數還有一個作用,就是協議回調函數的參數,用來讓上層區分網絡請求的。
第二個接口的第一個參數是NSURLRequest類型,用來設置網絡請求參數的,比如POST、要發送的數據流、HTTP信息頭等。第二個參數的作用跟第一個接口的第二個參數一樣。
該類對應的協議就不必談了,大家能看懂的。該類功能的具體實現,大家自己分析。
作者:yjh4866