LSAFHTTPClient 對所有請求進行統一管理,添加了兩個隊列:一個工作隊列,一個讀寫緩存的io隊列 LSAFHTTPClient.h 代碼如下: LSAFHTTPClient.m 代碼如下: LSBaseRequest 實現網路層的統一請求,在子類請求中調用基類的請求方法。 LSBaseRe ...
LSAFHTTPClient 對所有請求進行統一管理,添加了兩個隊列:一個工作隊列,一個讀寫緩存的io隊列
LSAFHTTPClient.h 代碼如下:
1 #import "AFNetworking.h" 2 3 @interface LSAFHTTPClient : AFHTTPRequestOperationManager 4 5 @property (nonatomic, strong) dispatch_queue_t workQueue;//Serail Send Request Queue 6 @property (nonatomic, strong) dispatch_queue_t iOSerialQueue; 7 8 +(LSAFHTTPClient*)shareClient; 9 10 typedef void (^LSRequestResultBlock)(id result, NSError *err); 11 12 -(BOOL)isHttpQueueFinished:(NSArray*)httpUrlArray; 13 @end
LSAFHTTPClient.m 代碼如下:
1 #import "LSAFHTTPClient.h" 2 #import "LSBaseRequest.h" 3 #import "LSHelper.h" 4 #import "AFHTTPRequestOperation.h" 5 #import "AFURLConnectionOperation.h" 6 #import "LSPathMacro.h" 7 #import <Foundation/Foundation.h> 8 @implementation LSAFHTTPClient 9 10 +(LSAFHTTPClient*)shareClient 11 { 12 static LSAFHTTPClient* _shareClient; 13 static dispatch_once_t onceToken; 14 dispatch_once(&onceToken, ^{ 15 _shareClient = [[LSAFHTTPClient alloc]initWithBaseURL:[NSURL URLWithString:LSURLHeadStatic]]; 16 [_shareClient.requestSerializer setTimeoutInterval:15]; //網路超時時間15S 17 18 //一個工作隊列,一個讀寫緩存的io隊列 19 _shareClient.workQueue = dispatch_queue_create("com.shareClient.workQueue", DISPATCH_QUEUE_SERIAL); 20 _shareClient.iOSerialQueue = dispatch_queue_create("com.shareClient.iOSerialQueue", DISPATCH_QUEUE_SERIAL); 21 }); 22 return _shareClient; 23 } 24 25 - (id)initWithBaseURL:(NSURL *)url 26 { 27 self = [super initWithBaseURL:url]; 28 29 if (!self) { 30 return nil; 31 } 32 return self; 33 } 34 - (void)dealloc 35 { 36 37 } 38 -(BOOL)isHttpQueueFinished:(NSArray*)httpUrlArray 39 { 40 NSLog(@"%ld",self.operationQueue.operationCount); 41 if(self.operationQueue.operationCount==0){ 42 return YES; 43 } 44 45 //add filter urlString.length==0 46 NSMutableArray* urlArray = [NSMutableArray array]; 47 for (NSString* currentUrl in httpUrlArray) { 48 if (currentUrl.length != 0) { 49 [urlArray addObject:currentUrl]; 50 } 51 } 52 53 //urlArray is empty 54 if(urlArray.count == 0){ 55 return YES; 56 } 57 58 for (AFHTTPRequestOperation* operation in self.operationQueue.operations) { 59 NSString* url = operation.request.URL.absoluteString; 60 for (NSString* baseUrl in urlArray) { 61 if ([url rangeOfString:baseUrl].location!=NSNotFound) { 62 return NO; 63 } 64 } 65 } 66 return YES; 67 } 68 @end
LSBaseRequest 實現網路層的統一請求,在子類請求中調用基類的請求方法。
LSBaseRequest.h 代碼如下:
1 #import <Foundation/Foundation.h> 2 #import "LSAFHTTPClient.h" 3 #import "LSGlobal.h" 4 #import "LSBaseState.h" 5 #import "LSErrorState.h" 6 #import "LSSuccessState.h" 7 #import "AESCrypt.h" 8 9 typedef enum{ 10 LSREQUESTMETHODGET=0, 11 LSREQUESTMETHODPOST=1 12 }LSREQUESTMETHOD; 13 14 @class LSBaseRequest; 15 16 @interface LSBaseRequest : NSObject 17 18 @property(nonatomic) LSREQUESTMETHOD requestMethod; //請求方式 19 @property(nonatomic, strong) NSString *methodName; //方法名 20 @property(nonatomic, strong) NSString *event; //觸發事件 21 @property(nonatomic, strong) NSString *cache; //是否緩存 22 @property(nonatomic) BOOL isGzip; //是否壓縮 23 @property (strong,nonatomic) id result; 24 @property(nonatomic, assign) long ret; //標識數據否更新 25 @property (strong,nonatomic)NSMutableDictionary* parametersDic; //參數字典 json 26 27 /** 重覆次數 */ 28 @property(nonatomic, assign) NSInteger numOfRepeat;//網路請求失敗後重覆的次數 29 30 /** 31 @brief 網路錯誤碼,通過此錯誤碼可以判斷出是否是取消請求造成網路失敗,從而不需要顯示無數據,7.11加 32 @note kCFURLErrorCancelled為取消請求 33 */ 34 @property (nonatomic, assign) NSInteger network_error_code; 35 36 - (void)setIntegerValue:(NSInteger)value forKey:(NSString *)key; 37 - (void)setDoubleValue:(double)value forKey:(NSString *)key; 38 - (void)setLongLongValue:(long long)value forKey:(NSString *)key; 39 - (void)setBOOLValue:(BOOL)value forKey:(NSString *)key; 40 - (void)setValue:(id)value forKey:(NSString *)key; 41 42 -(void)sendRequestSuccFinishBlock:(void(^)(LSBaseRequest* request))requestFinishBlock requestFailFinishBlock:(void(^)(LSBaseRequest* request))requestFailFinishBlock; 43 -(void)sendUpdateImageRequestSuccFinishBlock:(void(^)(LSBaseRequest* request))requestFinishBlock requestFailFinishBlock:(void(^)(LSBaseRequest* request))requestFailFinishBlock withImageData:(NSData*)imgData; 44 /* 45 * @brief 伺服器返回的數據解析成功後會調用 46 * @note 可以訪問self.result得到伺服器返回的結果,一定是NSDictionary類型。 47 * @note 對網路請求的數據結果進行封裝(可選) 子類實現 48 */ 49 -(id)processResultWithDic:(NSMutableDictionary*)resultDic; 50 51 /* 52 *@brief 請使用此方法取消網路請求 53 */ 54 +(void)cancelRequest; 55 56 /** 57 * @note 用戶初始化子類request,調用完畢self.methodName=@"xxxx"後,此getUrlName方法有效。 58 * @note 否則返回為空字元串. @"" 59 * @note 不允許子類實現 60 */ 61 +(NSString*)getUrlName; 62 /** 63 * @brief 此方法可以根據傳入的urlArray判斷是否http已經完成 64 * @note don't OVERRIDE this method 65 */ 66 +(BOOL)isHttpQueueFinished:(NSArray*)httpUrlArray; 67 68 /** 69 * @brief 此方法可以根據傳入的class類名判斷是否http已經完成 70 * @note don't OVERRIDE this method 71 * @example 72 NSArray* classNameArray = @[@"LSUpdateDataRequest", @"LSSearchGoodsRequest", 73 @"LSGoodsListRequest", @"LSCinemaListRequest"]; 74 BOOL isFinished = [LSBaseRequest isHttpQueueFinishedWithClassNameArray:classNameArray]; 75 */ 76 +(BOOL)isHttpQueueFinishedWithClassNameArray:(NSArray*)requestClassArray; 77 78 @end
LSBaseRequest.m 代碼如下:
1 #import <objc/objc.h> 2 #import <objc/runtime.h> 3 #import "LSBaseRequest.h" 4 #import "LSDesUtil.h" 5 #import "AFHTTPRequestOperation.h" 6 #import "LSCacheFile.h" 7 #import "LSServerResult.h" 8 #import "NSString+LSAdditional.h" 9 10 #define LSBASEREQUEST_METHODNAME_KEY @"LSBASEREQUEST_METHODNAME_KEY" 11 //uncomment folling line if you need to test request performance 12 //#define ENABLE_LSBASEREQUEST_LOG 13 14 #ifdef ENABLE_LSBASEREQUEST_LOG 15 #define RequestLog(fmt, ...) NSLog((@"%s [Line %d] %@ " fmt), __PRETTY_FUNCTION__, __LINE__,self, ##__VA_ARGS__) 16 #else 17 #define RequestLog(fmt, ...) 18 #endif 19 20 @interface LSBaseRequest () 21 { 22 void(^_requestSuccFinishBlock)(LSBaseRequest*); 23 void(^_requestFailFinishBlock)(LSBaseRequest*); 24 25 NSMutableDictionary* _httpBodyDic; 26 NSString * _key; 27 NSString * _webtime; 28 29 BOOL _isResetBlock;//是否進行複位block 30 NSInteger _internalRet;//內部使用的ret 31 BOOL _isFailBlockFinish; 32 33 } 34 35 @end 36 37 @implementation LSBaseRequest 38 39 -(id)init 40 { 41 self = [super init]; 42 if (self){ 43 _requestMethod = LSREQUESTMETHODPOST; 44 _parametersDic = [[NSMutableDictionary alloc] init]; 45 _httpBodyDic = [[NSMutableDictionary alloc] init]; 46 self.numOfRepeat = 1; //預設網路請求失敗請求3次 47 } 48 return self; 49 } 50 51 -(void)setMethodName:(NSString *)methodName 52 { 53 objc_setAssociatedObject([self class], LSBASEREQUEST_METHODNAME_KEY, methodName, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 54 _methodName = methodName; 55 } 56 - (void)setIntegerValue:(NSInteger)value forKey:(NSString *)key 57 { 58 [self setValue:[NSString stringWithFormat:@"%ld", value] forKey:key]; 59 } 60 - (void)setDoubleValue:(double)value forKey:(NSString *)key 61 { 62 [self setValue:[NSString stringWithFormat:@"%f", value] forKey:key]; 63 } 64 - (void)setLongLongValue:(long long)value forKey:(NSString *)key 65 { 66 [self setValue:[NSString stringWithFormat:@"%lld", value] forKey:key]; 67 } 68 - (void)setBOOLValue:(BOOL)value forKey:(NSString *)key 69 { 70 [self setValue:[NSString stringWithFormat:@"%d", value] forKey:key]; 71 } 72 - (void)setValue:(id)value forKey:(NSString *)key 73 { 74 //value只能是字元串,如果不是字元串類型,[LSHelper getSignParam]會crash,暫時未做處理。 75 if(!value){ 76 value = @""; 77 } 78 [_parametersDic setValue:value forKey:key]; 79 } 80 81 82 -(void)sendRequestSuccFinishBlock:(void(^)(LSBaseRequest* request))requestFinishBlock requestFailFinishBlock:(void(^)(LSBaseRequest* request))requestFailFinishBlock 83 { 84 _requestFailFinishBlock = requestFailFinishBlock; 85 _requestSuccFinishBlock = requestFinishBlock; 86 _isResetBlock = NO; 87 _isFailBlockFinish = NO; 88 self.result = nil; 89 //serail send request 90 // RequestLog(@"in MainThread begin send request"); 91 dispatch_async([LSAFHTTPClient shareClient].workQueue, ^{ 92 // RequestLog(@"serial send request"); 93 if (_requestMethod == LSREQUESTMETHODGET) { 94 [self doGetRequest]; 95 }else if(_requestMethod == LSREQUESTMETHODPOST){ 96 [self doPostRequest]; 97 } 98 }); 99 } 100 101 -(void)sendUpdateImageRequestSuccFinishBlock:(void(^)(LSBaseRequest* request))requestFinishBlock requestFailFinishBlock:(void(^)(LSBaseRequest* request))requestFailFinishBlock withImageData:(NSData*)imgData 102 { 103 _requestFailFinishBlock = requestFailFinishBlock; 104 _requestSuccFinishBlock = requestFinishBlock; 105 _isResetBlock = NO; 106 _isFailBlockFinish = NO; 107 self.result = nil; 108 //serail send request 109 // RequestLog(@"in MainThread begin send request"); 110 dispatch_async([LSAFHTTPClient shareClient].workQueue, ^{ 111 // RequestLog(@"serial send request"); 112 if (_requestMethod == LSREQUESTMETHODGET) { 113 [self doGetRequest]; 114 }else if(_requestMethod == LSREQUESTMETHODPOST){ 115 [self sendUpdateImageRequestWithData:imgData]; 116 } 117 }); 118 } 119 #pragma mark 發起Get或Post請求 120 -(void)doGetRequest 121 { 122 LSAFHTTPClient *httpClient = [LSAFHTTPClient shareClient]; 123 [self setparamesDic]; 124 httpClient.responseSerializer = [AFImageResponseSerializer serializer]; 125 [httpClient GET:_methodName parameters:_httpBodyDic success:^(AFHTTPRequestOperation *operation, id responseObject) { 126 self.result = responseObject; 127 _requestSuccFinishBlock(self); 128 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 129 [self handlerErrorResponse:error]; 130 }]; 131 132 } 133 134 -(void)doPostRequest 135 { 136 [self sendDataNumOfRepeat:self.numOfRepeat]; 137 //equestLog(@"serial postPath End"); 138 } 139 140 -(void)sendDataNumOfRepeat:(NSInteger)numOfRepeat{ 141 142 LSAFHTTPClient *httpClient = [LSAFHTTPClient shareClient]; 143 NSLog(@"%@", [httpClient.baseURL host]); 144 [self setparamesDic]; 145 146 httpClient.responseSerializer = [AFJSONResponseSerializer serializer]; 147 // [httpClient.requestSerializer setTimeoutInterval:15]; 148 [httpClient POST:_methodName parameters:_httpBodyDic success:^(AFHTTPRequestOperation *operation, id responseObject) { 149 //concurrent deal block 150 //RequestLog(@"concurrent deal block Success"); 151 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 152 [self hanleSuccessResponseWithOperation:operation response:responseObject]; 153 }); 154 155 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 156 //RequestLog(@"concurrent deal block Fail"); 157 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 158 if (numOfRepeat <= 1){ 159 [self handlerErrorResponse:error]; 160 }else{ 161 dispatch_async([LSAFHTTPClient shareClient].workQueue, ^{ 162 [self sendDataNumOfRepeat:numOfRepeat -1]; 163 }); 164 } 165 }); 166 167 }]; 168 } 169 170 - (void)sendUpdateImageRequestWithData:(NSData*)imgData 171 { 172 LSAFHTTPClient *httpClient = [LSAFHTTPClient shareClient]; 173 [self setparamesDic]; 174 [httpClient POST:@"member/upimg" parameters:_httpBodyDic constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { 175 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 176 // 設置時間格式 177 formatter.dateFormat = @"yyyyMMddHHmmss"; 178 NSString *str = [formatter stringFromDate:[NSDate date]]; 179 NSString *fileName = [NSString stringWithFormat:@"%@.jpg", str]; 180 [formData appendPartWithFileData:imgData name:@"img" fileName:fileName mimeType:@"image/jpeg"]; 181 } success:^(AFHTTPRequestOperation *operation, id responseObject) { 182 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 183 [self hanleSuccessResponseWithOperation:operation response:responseObject]; 184 }); 185 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 186 [self handlerErrorResponse:error]; 187 }]; 188 189 } 190 191 192 - (void)sendImagData:(NSData*)imageData 193 { 194 195 LSAFHTTPClient *httpClient = [LSAFHTTPClient shareClient]; 196 [self setparamesDic]; 197 198 [httpClient POST:@"member/upimg" parameters:_httpBodyDic constructingBodyWithBlock:^(id<AFMultipartFormData> formData) { 199 [formData appendPartWithFileData:imageData name:@"img" fileName:@"ios_header_img.jpg" mimeType:@"image/jpeg"]; 200 } success:^(AFHTTPRequestOperation *operation, id responseObject) { 201 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 202 [self hanleSuccessResponseWithOperation:operation response:responseObject]; 203 }); 204 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 205 [self handlerErrorResponse:error]; 206 }]; 207 208 209 } 210 211 212 -(void)setparamesDic 213 { 214 /* 215 body: params, time, sign, token 216 */ 217 218 NSString *device_name = [LSHelper deviceType]; 219 NSString *system_version = [LSHelper iOSVersion]; 220 NSString *timestamp = [LSHelper getTimeStamp]; 221 NSString *device_id = [LSHelper getCurrentDeviceUDID]; 222 NSString *device_type = @"ios"; 223 NSString *version_no = kSoftwareVersion; 224 NSString *token = [LSGlobal sharedGlobal].token; 225 NSString *channel_id = @"10000"; 226 227 [_httpBodyDic setValue:device_name forKey:@"device_name"]; 228 [_httpBodyDic setValue:system_version forKey:@"system_version"]; 229 [_httpBodyDic setValue:timestamp forKey:@"timestamp"]; 230 [_httpBodyDic setValue:token forKey:@"token"]; 231 [_httpBodyDic setValue:device_id forKey:@"device_id"]; 232 [_httpBodyDic setValue:device_type forKey:@"device_type"]; 233 [_httpBodyDic setValue:version_no forKey:@"version_no"]; 234 [_httpBodyDic setValue:channel_id forKey:@"channel_id"]; 235 [_httpBodyDic addEntriesFromDictionary:_parametersDic]; 236 237 //添加加密欄位 238 [_httpBodyDic setValue:[NSString getSignPara:_httpBodyDic andTime:nil] forKey:@"security"]; 239 } 240 #pragma mark 讀取寫入緩存 241 -(void)readCacheFile 242 { 243 //sync read for webtime and serverKey 244 NSString *md5file_token = [self mdt5FileName:@"token"]; 245 NSDictionary *dic = [LSCacheFile readFileName:md5file_token]; 246 if (dic) { 247 _webtime = [dic objectForKey:@"webtime"]; 248 _key = [dic objectForKey:@"serverkey"]; 249 } 250 251 //async read for local content 252 dispatch_async([LSAFHTTPClient shareClient].iOSerialQueue, ^{ 253 NSString *md5file_local = [self mdt5FileName:@"local"]; 254 NSMutableDictionary* resultDic = [LSCacheFile readFileName:md5file_local]; 255 if(resultDic){ 256 [self handlerSuccFinishResponseWithDic:resultDic isWeb:NO serverResult:nil]; 257 } 258 }); 259 } 260 261 -(void)writeCacheFileWithKey:(NSString *)serverkey webtime:(NSString *)webtime resultDic:(id)resultDic 262 { 263 //async write to local and token file 264 dispatch_async([LSAFHTTPClient shareClient].iOSerialQueue, ^{ 265 if (!serverkey || !webtime) { 266 DLog(@"%@, ERROR:serverkey or webtime is nil, write to cache failed", self); 267 return ; 268 } 269 NSString *md5file_token = [self mdt5FileName:@"token"]; 270 NSDictionary *dic = @{@"webtime":webtime,@"serverkey":serverkey}; 271 [LSCacheFile writeFileName:md5file_token data:dic]; 272 NSString *md5file_local = [self mdt5FileName:@"local"]; 273 [LSCacheFile writeFileName:md5file_local data:resultDic]; 274 }); 275 } 276 #pragma mark 處理返回的結果 277 -(void)hanleSuccessResponseWithOperation:(AFHTTPRequestOperation *)operation response:(id)responseObject 278 { 279 [self handlerResponse:responseObject serverKey:nil des:nil webtime:nil]; 280 } 281 -(void)handlerResponse:(id)responseObject serverKey:(NSString *)serverkey des:(NSString *)des webtime:(NSString *)webtime 282 { 283 LSServerResult *serverResult = [[LSServerResult alloc] init]; 284 serverResult.serverKey = serverkey; 285 serverResult.webTime = webtime; 286 287 NSData* clearData = responseObject; 288 NSError *error = nil; 289 NSMutableDictionary* resultDic = (NSMutableDictionary*)clearData; 290 // if (clearData) { 291 // resultDic = [LSHelper parserJsonData:clearData]; 292 // if(![resultDic isKindOfClass:[NSDictionary class]]) 293 // { 294 // resultDic = nil; 295 // } 296 // } 297 if (clearData && !error) 298 { 299 if ([_cache isEqualToString:@"true"]) { 300 _internalRet = [[resultDic objectForKey:@"ret"] longValue]; 301 if (_internalRet != kNetRetFlag) { 302 serverResult.resultDic = resultDic; 303 [self handlerSuccFinishResponseWithDic:resultDic isWeb:YES serverResult:serverResult]; 304 } 305 else{ 306 //需要處理清空finishblock的情況。同時還註意不要將緩存清掉。 307 [self handlerSuccFinishResponseWithNetFlag]; 308 } 309 }else{ 310 [self handlerSuccFinishResponseWithDic:resultDic isWeb:YES serverResult:serverResult]; 311 } 312 }else{ 313 //數據不是json格式 314 [self handlerErrorResponse:nil]; 315 } 316 } 317 318 /** 如果緩存先返回,而且設置了resetBlock標記,網路返回99999時候進行reset。 */ 319 -(void)handlerSuccFinishResponseWithNetFlag 320 { 321 dispatch_async(dispatch_get_main_queue(), ^{ 322 if(_isResetBlock){ 323 [self resetFinishBlock]; 324 } 325