如何将带参数的请求放入NSArray并稍后调用循环?

时间:2021-05-30 11:13:06

I want to call a unspecified number of URL requests which must be fired one after other. As the server can´t handle multiple requests with identical user-ID at the same time (only the last request is processed) i have to send my requests in an interval with about 1 seconds of gap. I did that within a dispatch_after block and increasing delays. But this is neither really secure nor elegant.

我想调用一个未指定数量的URL请求,这些请求必须一个接一个地被触发。由于服务器无法同时处理具有相同用户ID的多个请求(仅处理了最后一个请求),因此我必须以大约1秒的间隔发送我的请求。我在dispatch_after块内做了那个并且增加了延迟。但这既不安全也不优雅。

I´ve been just reading all day about GCD and want to try to change my code to send URL requests in a chain. My server connection class is build upon a NSURLConnection with asynchronuous request. That means it wouldn´t work with dispatch_async as the method call returns immediately back and the next request in the dispatch queue is called (which is probably immediately). But i have to wait for the response of the server until i may send the next request. My server connection class sends back via a delegate, but with dispatch_async it is never sending any deletate callbacks. Anyhow it wouldn´t work this way.

我一整天都在阅读有关GCD的内容,并希望尝试更改我的代码以在链中发送URL请求。我的服务器连接类是在具有异步请求的NSURLConnection上构建的。这意味着它不能与dispatch_async一起工作,因为方法调用会立即返回并调用调度队列中的下一个请求(可能是立即调用)。但我必须等待服务器的响应,直到我发送下一个请求。我的服务器连接类通过委托发回,但是使用dispatch_async,它永远不会发送任何deletate回调。无论如何它不会这样工作。

Probably it is better to put all requests into a NSArray and then call a method which will send requests from the array to the connection class and the delegate callback will pop the item from the array and sending the next request till all requests are done. Unfortunately i absolutely have no idea how i could store the requests and parameters in an array. Currently my call looks like that:

可能最好将所有请求放入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];
}

A part of the request parameters is already in an array. I could use this array and push the other request parameters into it and then sending the first parameter. And after server responded send the next request triggered by the callback from the delegate. Probably this would work.

请求参数的一部分已经在数组中。我可以使用这个数组并将其他请求参数推入其中,然后发送第一个参数。并且在服务器响应之后发送由委托回调触发的下一个请求。可能这会奏效。

But i´m just wondering if there isn´t andy way to que the requests a dispatch queue. But how could i que the delegates as well? Or what do i have to do that the queue will wait until the server responds? I´d like to avoid rewriting my server connection class from asynchronous to synchronous URLConnection which would probably make the difference.

但我只是想知道是否有方法将请求排入调度队列。但是我怎么能对代表们这样呢?或者我必须做什么,队列将等到服务器响应?我想避免将我的服务器连接类从异步重写为同步URLConnection,这可能会有所不同。

Can anybody point me to a solution with asynchronous URLConnection and dispatch_async?

有人能指出我使用异步URLConnection和dispatch_async的解决方案吗?

I haven´t seen the possibilites of NSOperation and NSOperationQueue yet. In the podcast of Jeff Kelley i´ve heard that the advantage of GCD over NSOperation is the dependencies feature. http://iphreaksshow.com/042-iphreaks-show-concurrency-with-jeff-kelley/

我还没有看到NSOperation和NSOperationQueue的可能性。在Jeff Kelley的播客中,我听说GCD优于NSOperation的优势在于依赖功能。 http://iphreaksshow.com/042-iphreaks-show-concurrency-with-jeff-kelley/

Or did i mix up everything? What would you recommend?

或者我混淆了一切?你会推荐什么?

1 个解决方案

#1


1  

A complete NSURLRequest represents a complete request by containing a path, query params or body, headers, etc. You can build several of these to represent your several server requests.

完整的NSURLRequest通过包含路径,查询参数或正文,标题等来表示完整的请求。您可以构建其中的几个来表示您的多个服务器请求。

NSURLConnection provides an asynch send (sendAsynchronousRequest:queue:completionHandler:). A naive way to sequence a series of requests, is to nest the requests in completion blocks as follows...

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

But it should be clear that this is a weak idea. You can get the same effect for sequencing an arbitrary number of requests with pretty compact code as follows:

但应该清楚的是,这是一个微弱的想法。使用非常紧凑的代码对任意数量的请求进行排序可以获得相同的效果,如下所示:

- (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];
    }];
}

Now, as you suggested, prepare several requests and place them in an array:

现在,正如您所建议的那样,准备几个请求并将它们放在一个数组中:

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);
}];

#1


1  

A complete NSURLRequest represents a complete request by containing a path, query params or body, headers, etc. You can build several of these to represent your several server requests.

完整的NSURLRequest通过包含路径,查询参数或正文,标题等来表示完整的请求。您可以构建其中的几个来表示您的多个服务器请求。

NSURLConnection provides an asynch send (sendAsynchronousRequest:queue:completionHandler:). A naive way to sequence a series of requests, is to nest the requests in completion blocks as follows...

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

But it should be clear that this is a weak idea. You can get the same effect for sequencing an arbitrary number of requests with pretty compact code as follows:

但应该清楚的是,这是一个微弱的想法。使用非常紧凑的代码对任意数量的请求进行排序可以获得相同的效果,如下所示:

- (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];
    }];
}

Now, as you suggested, prepare several requests and place them in an array:

现在,正如您所建议的那样,准备几个请求并将它们放在一个数组中:

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);
}];