我想调用数量不详的URL请求,这些请求必须一个接一个地触发。由于服务器无法同时处理具有相同用户ID的多个请求(只处理最后一个请求),我必须在大约1秒的间隔内发送请求。我是在一个dispatch_after阻塞和不断增加的延迟内完成的。但这既不安全也不优雅。
我已经读了一整天关于GCD的文章,想尝试更改我的代码以在链中发送URL请求。我的服务器连接类是基于具有异步请求的NSURLConnection构建的。这意味着它不能与dispatch_async一起工作,因为方法调用会立即返回,并且调度队列中的下一个请求会被调用(可能会立即调用)。但我必须等待服务器的响应,直到我可以发送下一个请求。我的服务器连接类通过委托发回,但使用dispatch_async,它永远不会发送任何deletate回调。无论如何,这样做是行不通的。
也许最好将所有请求放入NSArray中,然后调用一个方法,该方法将从数组向连接类发送请求,委托回调将从数组中弹出项目并发送下一个请求,直到所有请求都完成。不幸的是,我完全不知道如何将请求和参数存储在数组中。目前我的电话是这样的:
- (void)sendSettings
{
//NSLog(@"begins: %s", __FUNCTION__);
dataProtocol = [[BackgroundSoundConnection alloc] init];
[dataProtocol setDelegate:self];
//double delayInSeconds;
//dispatch_time_t popTime;
//delayInSeconds = 0.1f;
if (self.switch1.on)
{
if (![self.pinnedSettings.nextCall.globalId isEqualToString:self.sound.globalId]) {
[dataProtocol requestDataFromServer:[NSString stringWithFormat:@"setBackgroundSoundNextCall/%@", self.sound.globalId] httpMethod:@"PUT" sound:self.sound stickerType:@"nextCall" personMSISDN:nil];
}
} else {
if ([self.pinnedSettings.nextCall.globalId isEqualToString:self.sound.globalId]) {
[dataProtocol requestDataFromServer:[NSString stringWithFormat:@"disableBackgroundSoundNextcall"] httpMethod:@"PUT" sound:nil stickerType:nil personMSISDN:nil];
}
}
if (self.switch2.on)
{
if (![self.pinnedSettings.incomingCalls.globalId isEqualToString:self.sound.globalId]) {
[dataProtocol requestDataFromServer:[NSString stringWithFormat:@"setBackgroundSoundIncoming/%@", self.sound.globalId] httpMethod:@"PUT" sound:self.sound stickerType:@"incomingCalls" personMSISDN:nil];
}
} else {
if ([self.pinnedSettings.incomingCalls.globalId isEqualToString:self.sound.globalId]) {
[dataProtocol requestDataFromServer:[NSString stringWithFormat:@"disableBackgroundSoundIncoming"] httpMethod:@"PUT" sound:nil stickerType:nil personMSISDN:nil];
}
}
if (self.switch3.on)
{
if (![self.pinnedSettings.outgoingCalls.globalId isEqualToString:self.sound.globalId]) {
[dataProtocol requestDataFromServer:[NSString stringWithFormat:@"setBackgroundSoundOutgoing/%@", self.sound.globalId] httpMethod:@"PUT" sound:self.sound stickerType:@"outgoingCalls" personMSISDN:nil];
}
} else {
if ([self.pinnedSettings.outgoingCalls.globalId isEqualToString:self.sound.globalId]) {
[dataProtocol requestDataFromServer:[NSString stringWithFormat:@"disableBackgroundSoundOutgoing"] httpMethod:@"PUT" sound:nil stickerType:nil personMSISDN:nil];
}
}
for (int i = 0; i < [personArray count]; i++)
{
if (![personArray[i] connectedToServer])
{
NSLog(@"sound: %@", [personArray[i] soundId]);
NSLog(@"msisdn: %@", [personArray[i] personMSISDN]);
[dataProtocol requestDataFromServer:[NSString stringWithFormat:@"setBackgroundSoundContext/%@/%@", [personArray[i] soundId], [personArray[i] personMSISDN]] httpMethod:@"PUT" sound:self.sound stickerType:@"contextCalls" personMSISDN:[personArray[i] personMSISDN]];
}
}
[self animateViewAway:self.view];
}
一部分请求参数已在数组中。我可以使用这个数组并将其他请求参数推入其中,然后发送第一个参数。服务器响应后,发送由代理的回调触发的下一个请求。也许这会奏效。
但我只是想知道是否没有办法将请求发送到调度队列中。但是,我怎么能问代表们呢?或者我该怎么做才能让队列等待服务器响应?我想避免将我的服务器连接类从异步重写为同步URLConnection,这可能会有所不同。
有人能给我指一个异步URLConnection和dispatch_async的解决方案吗?
我还没有看到NSOperation和NSOperationQueue的可能性。在Jeff Kelley的播客中,我听说GCD相对于NSOperation的优势在于依赖性功能。http://iphreaksshow.com/042-iphreaks-show-concurrency-with-jeff-kelley/
还是我把一切都搞混了?你推荐什么?
完整的NSURLRequest
通过包含路径、查询参数或正文、标头等来表示完整的请求。您可以构建其中的几个来表示您的几个服务器请求。
NSURLConnection
提供异步发送(sendAsynchronousRequest:queue:completionHandler:
)。对一系列请求进行排序的一种简单方法是将请求嵌套在完成块中,如下所示。。。
[NSURLConnection sendAsynchronousRequest:request0 queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
[NSURLConnection sendAsynchronousRequest:request1 queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
// and so on... yikes, we'll have code in column 1000 pretty soon
但应该清楚的是,这是一个软弱的想法。您可以使用以下非常紧凑的代码对任意数量的请求进行排序,从而获得相同的效果:
- (void)doManyRequests:(NSArray *)requests withResults:(NSMutableArray *)results completion:(void (^)(void))completion {
if (!requests.count) {
return completion();
}
NSURLRequest *nextRequest = requests[0];
NSArray *remainingRequests = [requests subarrayWithRange:NSMakeRange(1, requests.count-1)];
[NSURLConnection sendAsynchronousRequest:nextRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
[results addObject:data];
[self doManyRequests:remainingRequests withResults:results completion:completion];
}];
}
现在,正如您所建议的,准备几个请求并将它们放在一个数组中:
NSURLRequest *request0 = // however you build this for a given user id
NSURLRequest *request1 = // etc.
NSURLRequest *request2 = // etc.
NSArray *requests = @[request0, request1, request2];
NSMutableArray *results = [NSMutableArray array];
[self doManyRequests:requests withResults:results completion:^{
NSLog(@"this will be an array of NSData objects %@", results);
}];