iOS开发 ☞ OS_dispatch_data

来源:互联网 发布:命名实体识别算法 编辑:程序博客网 时间:2024/05/17 02:03

有时在请求网络数据时并没有返回NSData,而是返回OS_dispatch_data

NSData实际上是仅仅提供接口的类簇,并且有很多种特别的实现,推断OS_dispatch_data是这样一种实现NSData is actually a class cluster which just provides the interface, and there are multiple special implementations for it around. It appears that OS_dispatch_data is such a special implementations made to pass data objects around blocks
OS_dispatch_data 是 dispatch_data_t (在iOS7和Mavericks上)可以用NSData无缝桥接,你可以很轻松的通过向下转型获得NSDataOS_dispatch_data is dispatch_data_t which has toll-free bridging with NSData on iOS 7 and Mavericks. You can simply cast it to NSData *.So, in your case you can write:NSData *dataCast = self.message.data;NSString *dataString = [[NSString alloc] initWithData:dataCast encoding:NSUTF8StringEncoding];

一件小事引发的血案:当我们使用原生API发送一个Get请求时,首先想到下面的方法

NSURLSession *session = [NSURLSession sharedSession];    NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"XXXX"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {    }];[task resume];

如果使用AFN则使用下面的方法

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];    manager.responseSerializer = [AFHTTPResponseSerializer serializer];    manager.responseSerializer.acceptableContentTypes =     [manager.requestSerializer setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];    [manager GET:@"XXXX" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {    }];

但是上面返回的确是OS_dispatch_data,而下面的responseObject返回的确是NSData,虽然OS_dispatch_data可以无缝桥接转换,但我们都知道AFN3.0封装的就是NSURLSession,那么从这一点入手,分析问题。

首先,分析一下是否是请求头的问题,
这里写图片描述

发现不一样的是User-Agent 和 Accept-Language 虽然这个并不会影响返回数据,但是还是看看AFN的源码吧

userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
// Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4    NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];    [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {        float q = 1.0f - (idx * 0.1f);        [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];        *stop = q <= 0.5f;    }];    [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];

与此同时 ,我无聊的将请求改为这样:

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];    config.HTTPAdditionalHeaders = @{                                     @"User-Agent":@"XXX/3.5.0 (iPhone; iOS 10.0; Scale/2.00)",                                     @"Accept-Language":@"zh-Hans-US;q=1, en;q=0.9"                                     }; NSURLSession *session = [NSURLSession sessionWithConfiguration:config];NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"XXXX"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {    }];[task resume];

显然,这与请求头毫无关系,那么就看看AFN是如何封装的吧

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request                               uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock                             downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock                            completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject,  NSError * _Nullable error))completionHandler {    __block NSURLSessionDataTask *dataTask = nil;    url_session_manager_create_task_safely(^{        dataTask = [self.session dataTaskWithRequest:request];    });    [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];    return dataTask;}

上面是AFN最内层方法,里面有我们想得到的dataTask = [self.session dataTaskWithRequest:request]; 瞬间恍然大悟,于是无聊的将网络请求更改为这样:

NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];    config.HTTPAdditionalHeaders = @{                                     @"User-Agent":@"XXXX/3.5.0 (iPhone; iOS 10.0; Scale/2.00)",                                     @"Accept-Language":@"zh-Hans-US;q=1, en;q=0.9"                                     };    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];    NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"XXXX"]];    [task resume];

遵守NSURLSessionDataDelegate,定义一个NSMutableData变量存储下载的NSData,实现下面的代理方法

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler{    self.allData = [NSMutableData data];    completionHandler(NSURLSessionResponseAllow);}- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{    [self.allData appendData:data];}- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{    NSLog(@"result: %@", self.allData);}
1 0
原创粉丝点击