iOS NSURLSessionUploadTask 响应数据
Posted
技术标签:
【中文标题】iOS NSURLSessionUploadTask 响应数据【英文标题】:iOS NSURLSessionUploadTask response data 【发布时间】:2014-07-17 11:26:17 【问题描述】:我已经成功实现了 NSURLSessionUploadTask 并在后台和前台工作。但是读取响应数据时出现问题。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
NSLog(@"1 DATA:\n%@\nEND DATA\n", [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]);
[self.responseData appendData:data];
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
if (!error)
NSLog(@"AT THE END DATA:\n%@\nEND DATA\n", [[NSString alloc] initWithData: self.responseData encoding: NSUTF8StringEncoding]);
[self parsingJSONResponse:self.responseData];
else
NSLog(@"HTTP uploading error : %@", error);
这些是以上两个 NSLog 的输出
1 数据: "成功":true,"数据":["uuid":"8BE7DF37-9DA1-44D2-B48C-D012F699A9B1","id":266626,"uuid":"3406D865-1A41-4FC6-BA0B- 0638F17757CC","id":266656],"errors":[],"entityName":"LeadProfile" 结束数据
最后数据: "成功":true,"数据":["uuid":"8BE7DF37-9DA1-44D2-B48C-D012F699A9B1","id":266626,"uuid":"3406D865-1A41-4FC6-BA0B- 0638F17757CC","id":266656],"errors":[],"entityName":"LeadProfile""success":true,"data":["uuid":"8BE7DF37-9DA1-44D2- B48C-D012F699A9B1","id":266626,"uuid":"3406D865-1A41-4FC6-BA0B-0638F17757CC","id":266656],"errors":[],"entityName":"LeadProfile " 结束数据
我想知道为什么这会给我一个上传任务两个不同的响应。 self.responseData
在每个位置上有何不同?
有人认为这是因为苹果网站上提到的原因吗? (因为 NSData 对象通常是由多个不同的数据对象拼凑而成,所以尽可能使用 NSData 的 enumerateByteRangesUsingBlock: 方法来遍历数据而不是使用 bytes 方法(将 NSData 对象扁平化为单个内存块)@987654321 @
【问题讨论】:
【参考方案1】:你问:
我想知道为什么这会给我一个上传任务两个不同的响应。
self.responseData
在每个位置上有何不同?
这无疑是因为responseData
没有正确或在正确的时间实例化。 (我倾向于在didReceiveResponse
中执行此操作。)请注意,您不会在didReceiveData
中查看responseData
。您正在查看data
。我建议在didReceiveData
中附加data
后立即检查responseData
,我相信你也会在那里看到它加倍。问题是为什么它没有正确实例化/初始化。
有人认为这是因为苹果网站上提到的原因吗?
“因为
NSData
对象通常是由多个不同的数据对象拼凑而成,所以尽可能使用NSData
的enumerateByteRangesUsingBlock:
方法来遍历数据而不是使用bytes方法(这会使NSData
对象到单个内存块中)。”
不,这是一个完全不相关的问题。我敢肯定这里的问题要平凡得多。
很遗憾,我们这里没有足够的代码来诊断确切的问题。
【讨论】:
【参考方案2】:您仅收到部分数据。您的委托方法应连接交付的每个数据对象的内容,以使用 NSMutableData 对象为 URL 加载构建完整数据。
【讨论】:
self.responseData 是一个 NSMutableData ,每次收到数据时我都会附加它。您是否建议使用 NSMutableData 的任何其他方式? 检查任务状态:task.state == NSURLSessionTaskStateCompleted 并确保 countOfBytesExpectedToReceive 和 countOfBytesReceived 相等。除此之外,它可能与请求连接是否保持活动有关,甚至与您解析 json 的方式有关...... 顺便说一句,你不能总是依赖expectedContentLength
。正如NSURLResponse
的文档所说:“一些协议实现将内容长度作为响应的一部分进行报告,但并非所有协议都保证能提供这么多数据。客户端应该准备好处理或多或少的数据。”更糟糕的是,有时他们根本无法确定内容大小,并且会报告一个负数(例如,分块响应或压缩响应)。最重要的是,应该非常谨慎地使用接收到的字节数来确定是否完成。【参考方案3】:
像documentation says一样,接收到的数据可能是不连续的。
所以,这可能是一个可能的实现:
- (void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
if (!self.responseData)
NSUInteger capacity = 0;
if (dataTask.response.expectedContentLength != NSURLResponseUnknownLength)
capacity = (NSUInteger)dataTask.response.expectedContentLength;
self.responseData = [[NSMutableData alloc] initWithCapacity:capacity];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop)
[self.responseData appendBytes:bytes length:byteRange.length];
];
您对- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
的实现是正确的。
【讨论】:
【参考方案4】:我找到了解决这个问题的方法。但这可能不是一个正确的答案。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
//Get Hex string from 'data'. There can be a solution directly add bytes to NSData (using 'enumerateByteRangesUsingBlock') rather than convert to Hex string
NSMutableString *string = [NSMutableString stringWithCapacity:data.length * 3];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop)
for (NSUInteger offset = 0; offset < byteRange.length; ++offset)
uint8_t byte = ((const uint8_t *)bytes)[byteRange.location + offset];
if (string.length == 0)
[string appendFormat:@"%02X", byte];
else
[string appendFormat:@" %02X", byte];
];
//Hex string to NSdata
NSString *command = string;
command = [command stringByReplacingOccurrencesOfString:@" " withString:@""];
NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = '\0','\0','\0';
for (int i = 0; i < ([command length] / 2); i++)
byte_chars[0] = [command characterAtIndex:i*2];
byte_chars[1] = [command characterAtIndex:i*2+1];
whole_byte = strtol(byte_chars, NULL, 16);
[commandToSend appendBytes:&whole_byte length:1];
NSLog(@"1 >>>>>>>>>>>>>>>>>>> %@", [NSString stringWithUTF8String:[commandToSend bytes]]);
【讨论】:
不,这肯定不是正确的解决方案。事实上,如果NSData
实际上被分割成非连续的块,那么这个解决方案就行不通(因为这是取自another answer,虽然没有正确归因于这是不正确的)。 bytes
的索引是错误的。其他答案已修复。而且,对您来说幸运的是,它不会经常将NSData
拆分为不连续的块,因此您可能没有遇到隐藏在上述代码中的错误。这仅适用于您碰巧不再附加到responseData
。以上是关于iOS NSURLSessionUploadTask 响应数据的主要内容,如果未能解决你的问题,请参考以下文章