如何将带有参数的请求放入NSArray中,然后在循环中调用



我想调用数量不详的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);
}];

相关内容

最新更新