RestKit - Process one REST operation at a time

Deadly 提交于 2019-12-23 04:02:52

问题


I'm using RestKit 0.20.3 and have some REST operations that needs to be done in a certain order (the response from one REST operation needs to be included in the request parameter mapping for the next).

I tried setting up the queue to handle one operation at a time like this:

RKObjectManager.sharedManager.operationQueue.maxConcurrentOperationCount = 1;

And adding the operations like this:

for (id insertedObject in insertedObjects) {
    [RKObjectManager.sharedManager postObject:insertedObject path:nil parameters:nil success:nil failure:nil];
}

But I get an error, because the first operation is not fully completed before the other start.

When inspecting the logs, it seems like it is executed like this:

  1. REST operation 1 - Request mapping
  2. REST operation 2 - Request mapping
  3. REST operation 3 - Request mapping
  4. REST operation 1 - HTTP call and response mapping
  5. REST operation 2 - HTTP call and response mapping
  6. REST operation 3 - HTTP call and response mapping

I have already tried setting operation dependencies, but that does not make a difference.

I need one REST operation to be completed at a time. How do I do this in RestKit?


回答1:


PROBLEM

RestKit uses multiple NSOperation for one REST operation, so all request mappings will be queued first with the code in the question. So when the first request mapping is executed and queuing the actual HTTP request, it gets queued behind the first two request mapping operations.

SOLUTION

Queue the next operation after the first one finishes.

Example with recursion:

- (void)sync {
    NSArray *objectsToPostInOrder = ...;

        for (id objectToPost in objectsToPostInOrder) {
            [RKObjectManager.sharedManager postObject:objectToPost path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
                // Proceed with next if everything went OK
                [self sync];
            } failure:^(RKObjectRequestOperation *operation, NSError *error) {
                // Don't continue posting as they are dependent on each other
                [MyHUD showErrorWithStatus:error.localizedDescription];
            }];

            return;
        }
    }
}



回答2:


I managed to make it work by defining a custom asynchronous NSOperation, which uses RestKit's object get and does not indicate it is finished before RestKit's success/failure block is executed. These custom operations are then added into a separate queue (not RestKit's operation's queue) with maxConcurrentOperationCount set to 1, or you can define inter-operation dependencies as you want.




回答3:


An older question, but a common recurring problem:

This kind of asynchronous problem can be easily solved with a "Promise" (please read more about here in this wiki:Futures and Promises for a general instruction).

A "Promise" represents the eventual result of an asynchronous method. Eventual it becomes either the value you waiting for or an error.

You can "chain" such asynchronous methods in a way that guarantees that the "next" method is only called when the first has been finished successfully. And, there's also a way to "catch" errors that might have been "thrown" from an asynchronous method.

First, you need to wrap your NSOperationthat invokes the request into an asynchronous method that returns a promise:

- (Promise*) performRequestWithParams(NSDictionary* params);

Note, this is an asynchronous method. It returns immediately returning a "pending" promise. The promise is "resolved" eventually when the operation finishes by the NSOperation which you have to implement in the wrapper method.

Now, in order to "continue" with the next operation when the first finishes, you define a continuation using then as shown below:

Promise* promise = [self performRequestWithParams:params];
promise.then(^id(NSArray* result) {
    // We enter here, when the 1. REST op finished successfully:
    // note: here, `result` is the _result_ of the async operation above 
    // which was a JSON returned from the service and parsed into an array.

    // Obtain a value from the result:
    id x = result[0][@"someKey"];

    // Create a new JSON representation which is the input for the next REST operation:
    NSDictionary* params = ...; 

    // Now, invoke the 2. REST op asynchronously:
    return [self performRequestWithParams:params];
}, nil)
.then(^id(NSArray* result) {
    // We enter here, when the 2. REST op finished successfully:
    id x = result[0][@"someKey"]; // obtain a value from some dictionary
    NSDictionary* params = ...; // create a new JSON         
    // Now, invoke the next async method:
    return [self performRequestWithParams:params];
}, nil)
... // 3., 4., ... add more REST operations

// In case of an error in *any* of the operations above, let us "catch" it here:
.then(nil, ^id(NSError* error){
    NSLog(@"Error: %@", error);
});

Note: you can use a NSOperationQueue to control how many requests your program should execute concurrently. The continuations defined with the promise above are orthogonal to the constraints of the NSOperationQueue. That is, you can use the same NSOperationQueue which is configured to execute for example four concurrent operations, and which executes any other unrelated REST operation in parallel without disrupting the control flow of the "serialized" continuations above.

There are a couple of Promise libraries around. I'm the author of one of it. The project is open source available on GitHub: RXPromise.




回答4:


Works well for me so far.

AFRKHTTPClient *client = [[AFRKHTTPClient alloc] initWithBaseURL:self.baseUrl];
client.operationQueue.maxConcurrentOperationCount = 1;

RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
objectManager.operationQueue.maxConcurrentOperationCount = 1;
[RKObjectManager setSharedManager:objectManager];


来源:https://stackoverflow.com/questions/18993954/restkit-process-one-rest-operation-at-a-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!