我需要从服务器获取图像信息,例如图像名称,图像ID。然后使用image id作为参数之一进行发布,获取图像实际数据。更具体地说,我应该得到三个图像。
首先,我使用getImageInfo来获取图像信息。
- (void)getImageInfo {
// compose request
NSUserDefaults *getUserInfo = [NSUserDefaults standardUserDefaults];
NSString *uid = [getUserInfo objectForKey:@"uid"];
NSString *checkCode = [getUserInfo objectForKey:@"checkCode"];
NSString *data = [NSString stringWithFormat:@"uid=%@&yangzhengma=%@", uid, checkCode];
NSURL *url = [NSURL URLWithString:@"http://121.199.35.173:8080/xihuan22dcloud/services/Shibietupianservice/serviceGetallshibietu"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPBody = [data dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPMethod = @"POST";
[[self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
if (!error) {
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
// parse data in ram and put into images' imageInfos array
[self.images parseImageInfo:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]];
[self getImageRawData];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
}
}] resume];}
然后我使用getImageRawData来获取三个图像数据。
- (void)getImageRawData {
// compose request dynamically
NSUserDefaults *getUserInfo = [NSUserDefaults standardUserDefaults];
NSString *uid = [getUserInfo objectForKey:@"uid"];
NSString *checkCode = [getUserInfo objectForKey:@"checkCode"];
NSURL *url = [NSURL URLWithString:@"http://121.199.35.173:8080/xihuan22dcloud/services/Shibietupianservice/serviceGetthetupian"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSInteger count = 0;
for (ImageInformation *temp in self.images.imageInfos) {
NSString *data = [NSString stringWithFormat:@"uid=%@&yangzhengma=%@&tupianid=%@", uid, checkCode, temp.imageId];
request.HTTPBody = [data dataUsingEncoding:NSUTF8StringEncoding];[[self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
// if client side is no errors, continue
if (!error) {
// if server side is no errors, continue
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
NSLog(@"图片内容:%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
// in ram and put into images' imageRawData array
[self.images parseImageRawData:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] withImageId:temp.imageId withIndex:count];
// store data to disk
// NSString *path = [[NSString alloc] initWithFormat:@"image%@", temp.imageId];
// [FCFileManager writeFileAtPath:path content:data];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
}
}] resume];
count++;
}}
在这里,它将循环三次,三个响应返回,只有最后一个完成,其他包含错误消息,或者有时不完整的原始数据。现在我正在深入研究并发编程指南,我猜串行队列可能会解决这个问题。
输出如下:
2014-12-16 22:38:48.739 WeddingNewVersion[997:83366] 图片内容:<ns:serviceGetthetupianResponse xmlns:ns="http://serviceimpl.my.com"><ns:return>error</ns:return></ns:serviceGetthetupianResponse>
2014-12-16 22:38:48.749 WeddingNewVersion[997:83366] 图片内容:<ns:serviceGetthetupianResponse xmlns:ns="http://serviceimpl.my.com"><ns:return>error</ns:return></ns:serviceGetthetupianResponse>
2014-12-16 22:38:51.943 WeddingNewVersion[997:83366] 图片内容:<ns:serviceGetthetupianResponse xmlns:ns="http://serviceimpl.my.com"><ns:return>/9j/...(complete data)...9k=%%226654474.0</ns:return></ns:serviceGetthetupianResponse>
请求参数:
2014-12-17 14:59:25.364 WeddingNewVersion[1875:226651] uid=6&yangzhengma=odWoDXWcBv1jOrEhywkq7L&tupianid=41
2014-12-17 14:59:25.368 WeddingNewVersion[1875:226651] uid=6&yangzhengma=odWoDXWcBv1jOrEhywkq7L&tupianid=42
2014-12-17 14:59:25.368 WeddingNewVersion[1875:226651] uid=6&yangzhengma=odWoDXWcBv1jOrEhywkq7L&tupianid=43
问题可能不在撰写请求中。
----------------------------------------------- -update1 ----------------------------------------------- < / p>
我试图将会话的数据任务放入串行队列。失望,这不起作用。
dispatch_async(self.serialQueue, ^{
[[self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){...}] resume];
});
同时,我将session的delegateQueue设为nil,引用说如果为nil,则会话创建一个串行操作队列,用于执行所有委托方法调用和完成处理程序调用。
现在我仍然很困惑如何做对。
----------------------------------------------- UPDATE2 ------------------------------------------------ < / p>
我将[NSThread sleepForTimeInterval:0.5]添加到分派到串行队列的块中。
dispatch_async(self.serialQueue, ^{
[[self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){...}] resume];
[NSThread sleepForTimeInterval:0.5];
});
它不起作用。这三个答案是完整的,但它们都是一样的。
提前谢谢!
答案 0 :(得分:0)
我只是在猜测,因为我从未尝试过,但可能你的数据任务都使用了相同的TCP端口。
如果将它们序列化,那将是正常的 - 按顺序依次排列 - 但如果它们重叠,那么服务器将收到乱码的HTTP请求:
GET /foo
GET /bar
GET /baz
服务器会看到的内容可能是:
GET /fGET /baroo
GET /baz
你的第三个请求确实有效可能是时间上的意外。
如果您绝对要求同时发出三个请求,可以通过多种方式打开三个不同的端口。我不知道如何使用Cocoa和Objective-C,但你可以使用C和Berkeley Socket系统调用来做到这一点。 Cocoa / Cocoa Touch网络方法只是套接字的包装。
答案 1 :(得分:0)
有几点想法:
您使用单个NSMutableURLRequest
实例的技巧,并为每个请求重复变更(先前的请求仍在进行中),这很奇怪。
本着线程安全的精神,我会为每个并发请求使用单独的NSMutableURLRequest
。您不希望冒险让发出这些请求的线程改变请求对象,而某些后台线程执行其中一个先前请求。 (参见线程编程指南中的Apple Thread Safety Summary,其中指出可变类通常不是线程安全的。)
话虽如此,NSURLConnection
文档给我们的印象是这个请求对象会被复制,从而缓解了这个问题。我在NSURLSession
文档中没有看到这种保证(虽然我怀疑它做同样的事情)。
我不认为这是问题所在(如果这是问题,问题可能比你报告的问题更不稳定,而且,我怀疑NSURLSession
正在优雅地处理这个问题,无论如何),但作为良好的线程安全编码习惯,谨慎的做法是让每个并发请求都有自己的NSMutableURLRequest
对象。
您已确认请求中使用的信息有效。
如果你想把它提升到一个新的水平,你可以使用Charles(或Wire Shark或你喜欢的任何工具)来观察实际的请求。这些工具对于调试这些问题非常宝贵。
如果你观察Charles的请求并确认它们是有效的,那么这绝对可以消除客户端问题。
奇怪的是,您没有从NSError
收到dataTaskWithRequest
个对象。您也没有从服务器接收200以外的statusCode
。这意味着您的请求已成功发送到服务器并由服务器接收。
相反,服务器正在处理请求,但在完成请求时遇到问题。这让我想知道服务器代码本身。我怀疑服务器代码中存在阻止并发操作发生的事情(例如,在请求期间锁定某些共享资源,例如临时文件或SQL表)。我会仔细查看服务器代码并确保没有潜在的争用问题。
此外,我会修改服务器代码,而不是简单地报告&#34;错误&#34;,而是产生有意义的错误消息(例如系统提供的错误消息,错误代码等)。您的服务器正在检测错误,因此您应该让它准确地告诉您错误是什么。
注意,我明确建议您不要按顺序执行请求。这是不可取的。虽然它可以解决当前的问题,但是你会付出巨大的性能损失,并且它不具备可扩展性。请记住,您必须优雅地处理并发请求,因为您可能会在某个时刻拥有该应用的多个用户。
我会仔细查看服务器代码,在错误消息中添加更多调试信息,以便跟踪问题。
答案 2 :(得分:0)
我把请求放入for循环,它可以工作。关于NSMutableRequest和NSURLSession的抢劫的第一个想法似乎是对的,我试图抓住整个想法。谢谢你的回答。无论如何,这是代码。
for (ImageInformation *temp in self.images.imageInfos) {
// compose request dynamically
NSURL *url = [NSURL URLWithString:@"http://121.199.35.173:8080/xihuan22dcloud/services/Shibietupianservice/serviceGetthetupian"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSString *data = [NSString stringWithFormat:@"uid=%@&yangzhengma=%@&tupianid=%@", uid, checkCode, temp.imageId];
request.HTTPBody = [data dataUsingEncoding:NSUTF8StringEncoding];
// data task
dispatch_async(self.serialQueue, ^{
[[self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
// if client side is no errors, continue
if (!error) {
// if server side is no errors, continue
NSHTTPURLResponse *httpResp = (NSHTTPURLResponse*) response;
if (httpResp.statusCode == 200) {
// in ram and put into images' imageRawData array
[self.images parseImageRawData:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] withImageId:temp.imageId];
// store data to disk
// [FCFileManager writeFileAtPath:path content:data];
// dispatch display image task to main
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.images.imageDrawDatasDic count] == [self.images.imageInfos count]) {
[self.tableView reloadData];
}
});
}
}
}] resume];
[NSThread sleepForTimeInterval:0.5];
});
}
}