iOS学习----------AFNetworking(4)responseSerialization
来源:互联网 发布:qq一手数据出售群 编辑:程序博客网 时间:2024/05/22 15:33
在AFN中,通过类AFURLResponseSerialization对服务器返回的数据进行格式化(json/xml…),下面对这个类中主要的方法进行解析。
AFURLResponseSerialization.h文件
协议:AFURLResponseSerialization
//主要是判断返回的response是否可用- (BOOL)validateResponse:(NSHTTPURLResponse *)response data:(NSData *)data error:(NSError * __autoreleasing *)error{ BOOL responseIsValid = YES; NSError *validationError = nil; // 简单的为空判断和类型判断,注意如果response为空或类型不对,反而responseValid为YES if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) { // 如果response对应的mimeType不被这个ResponseSerializer所接受,那么就认为Response不可用//acceptableContentTypes保存了 每个类能解析的内容的类型 /* json为:@"application/json",@"text/html", @"text/json", @"text/javascript" */ if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]]) { //response不可用时候的处理 // 会返回unacceptable content-type的信息,并将错误信息记录在了mutableUserInfo中 if ([data length] > 0 && [response URL]) { NSMutableDictionary *mutableUserInfo = [@{NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]], NSURLErrorFailingURLErrorKey:[response URL], AFNetworkingOperationFailingURLResponseErrorKey: response,} mutableCopy]; if (data) {mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data; } // 利用mutableUserInfo构建一个NSError对象 validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError); } responseIsValid = NO; } // 判断返回的statusCode是否被允许 如果statuscode不在acceptableStatusCodes中那么response不可以处理error // self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) { NSMutableDictionary *mutableUserInfo = [@{ NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode], NSURLErrorFailingURLErrorKey:[response URL], AFNetworkingOperationFailingURLResponseErrorKey: response, } mutableCopy]; if (data) {mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data; } validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError); responseIsValid = NO; } } if (error && !responseIsValid) { *error = validationError; } return responseIsValid;}
静态方法对error进行处理
static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) { if (!error) { return underlyingError; } if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) { return error; } NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy]; mutableUserInfo[NSUnderlyingErrorKey] = underlyingError; return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo];}
AFJSONResponseSerializer类
对父类的- (id)responseObjectForResponse:(NSURLResponse )response data:(NSData )data error:(NSError __autoreleasing )error进行重写
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{ // 判断当前response是否有效 if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { // 还记得validateResponse:中如果content-type不满足,那么产生的validationError就是Domain为AFURLResponseSerializationErrorDomain,code为NSURLErrorCannotDecodeContentData if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { // 因为不支持这个content-type,所以不用解析了,直接返回nil return nil; } } id responseObject = nil; NSError *serializationError = nil; // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization. // See https://github.com/rails/rails/issues/1742 // 对于'head :ok',Rails返回的是一个空格 (这是Safari上的一个bug),并且这样的JSON格式不会被NSJSONSerialization解析。 // 如果是单个空格,就不解析 BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]]; if (data.length > 0 && !isSpace) { responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError]; } else { return nil; } // 如果需要移除JSON数据中对应value为空(nil或NSNull)的key,那么就使用AFJSONObjectByRemovingKeysWithNullValues函数 // AFJSONObjectByRemovingKeysWithNullValues通过递归的方法,把JSON中NSDictionary的数据(不包括NSArray)中的对应value为空的key移除 if (self.removesKeysWithNullValues && responseObject) { responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions); } if (error) { // 如果serializationError不为空,那么最终的error其实就是serializationError *error = AFErrorWithUnderlyingError(serializationError, *error); } return responseObject;}
AFXMLParserResponseSerializer类
返回一个NSXMLParser的解析器对xml数据进行解析 e
- (id)responseObjectForResponse:(NSHTTPURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{ if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { return nil; } } // 使用NSXMLParser解析NSData数据 return [[NSXMLParser alloc] initWithData:data];}
AFPropertyListResponseSerializer类
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{ if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { return nil; } } id responseObject; NSError *serializationError = nil; // 使用NSPropertyListSerialization来解析NSData数据 if (data) { responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError]; } // 如果serializationError不为空,那么最终的error其实就是serializationError if (error) { *error = AFErrorWithUnderlyingError(serializationError, *error); } return responseObject;}
AFImageResponseSerializer类
类型:@”image/tiff”, @”image/jpeg”, @”image/gif”, @”image/png”, @”image/ico”, @”image/x-icon”, @”image/bmp”, @”image/x-bmp”, @”image/x-xbitmap”, @”image/x-win-bitmap”
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{ if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { return nil; } } // iOS和TV平台默认automaticallyInflatesResponseImage为YES // 下面的NSData转图片的方法 if (self.automaticallyInflatesResponseImage) { //automaticallyInflatesResponseImage设置为yes:在后台对图片进行处理,而不是在main线程中 return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale); } else { return AFImageWithDataAtScale(data, self.imageScale); } return nil;}
获取到图片后的两种处理方式
第一种automaticallyInflatesResponseImage设置为yes:在后台对图片进行处理,而不是在main线程中static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) { if (!data || [data length] == 0) { return nil; } CGImageRef imageRef = NULL; CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); if ([response.MIMEType isEqualToString:@"image/png"]) { imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) { imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); if (imageRef) { CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef); CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace); // CGImageCreateWithJPEGDataProvider does not properly handle CMKY, so fall back to AFImageWithDataAtScale if (imageColorSpaceModel == kCGColorSpaceModelCMYK) { CGImageRelease(imageRef); imageRef = NULL; } } } CGDataProviderRelease(dataProvider); UIImage *image = AFImageWithDataAtScale(data, scale); if (!imageRef) { if (image.images || !image) { return image; } imageRef = CGImageCreateCopy([image CGImage]); if (!imageRef) { return nil; } } size_t width = CGImageGetWidth(imageRef); size_t height = CGImageGetHeight(imageRef); size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); if (width * height > 1024 * 1024 || bitsPerComponent > 8) { CGImageRelease(imageRef); return image; } // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate size_t bytesPerRow = 0; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace); CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); if (colorSpaceModel == kCGColorSpaceModelRGB) { uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask);#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wassign-enum" if (alpha == kCGImageAlphaNone) { bitmapInfo &= ~kCGBitmapAlphaInfoMask; bitmapInfo |= kCGImageAlphaNoneSkipFirst; } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) { bitmapInfo &= ~kCGBitmapAlphaInfoMask; bitmapInfo |= kCGImageAlphaPremultipliedFirst; }#pragma clang diagnostic pop } CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); CGColorSpaceRelease(colorSpace); if (!context) { CGImageRelease(imageRef); return image; } CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef); CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context); CGContextRelease(context); UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation]; CGImageRelease(inflatedImageRef); CGImageRelease(imageRef); return inflatedImage;}#endif第二种:直接通过Data转为imagestatic UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) { UIImage *image = [UIImage af_safeImageWithData:data]; if (image.images) { return image; } return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation];}static NSLock* imageLock = nil;+ (UIImage *)af_safeImageWithData:(NSData *)data { UIImage* image = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ imageLock = [[NSLock alloc] init]; }); [imageLock lock]; image = [UIImage imageWithData:data]; [imageLock unlock]; return image;}
AFCompoundResponseSerializer类
如果返回的类型不确定就用这个方法先去确定类型找到合适的Serializer,然后再进行处理
- (id)responseObjectForResponse:(NSURLResponse *)response data:(NSData *)data error:(NSError *__autoreleasing *)error{ // 可能确实不能确定返回的responsed的content-type,此时可以使用AFCompoundResponseSerializer // 总会找到合适的Serializer for (id <AFURLResponseSerialization> serializer in self.responseSerializers) { if (![serializer isKindOfClass:[AFHTTPResponseSerializer class]]) { continue; } NSError *serializerError = nil; id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError]; if (responseObject) { if (error) { *error = AFErrorWithUnderlyingError(serializerError, *error); } return responseObject; } } return [super responseObjectForResponse:response data:data error:error];}
到此为止AFNetworking中对请求和响应的序列化操作结束,下面就是最重要的请求的方式。
- iOS学习----------AFNetworking(4)responseSerialization
- iOS开发--AFNetworking数据请求
- IOS -AFNetworking 简介及使用
- iOS学习----------AFNetworking(5)NSURLSessionTask创建
- iOS开发-在Swift里使用AFNetworking方法
- iOS学习----------AFNetworking(1)网络监控
- iOS学习----------AFNetworking(3)request创建《post请求》
- [AFNetworking]源代码分析--AFURLRequestSerialization.h
- AFNetWorking 3.0请求返回NSData类型数据解决方案--iOS开发
- AFNetWorking 请求返回NSData类型数据解决方案--iOS开发
- iOS学习----------AFNetworking(2)request创建和请求参数的序列化
- iOS之网络请求初解-AFNetworking(包含图片上传)
- AFNetWorking实现SOAP消息发送 ---Web Service
- AFNetworking速成教程(1)--cpf
- xcode文件找不到---“AFNetworking.h”file not found
- xcode文件找不到---“AFNetworking.h”file not found
- xcode文件找不到---“AFNetworking.h”file not found
- IOS学习-HelloWorld
- 《Effective C++》学习笔记——条款40
- Android Camera数据流分析全程记录(非overlay方式)
- try块和异常处理,断言assert
- sessionStorage localStorage 和 cookie 之间的区别转
- IOS面试题总结--UIView和CALayer的层级关系和区别
- iOS学习----------AFNetworking(4)responseSerialization
- 设计模式之责任链模式
- ListView在Activity和Fragment中的显示和使用
- 三条足以让电脑死机的命令(.bat文件)
- POJ 3176 Cow Bowling
- BASIC-15字符串对比字符串 大小写VIP试题
- 常用的linux命令
- Android软件开发随笔笔记第一讲
- 你是不是文艺