多部分NSArray Post AFNetworking

时间:2015-11-09 20:50:52

标签: ios objective-c sqlite afnetworking

我有一个很大的NSArray我想要拆分成块并发送到我的Web服务器,完成每个块后,我需要更新我的SQLite DB中与每个数组块中的每个项相关的字段。

这是我当前正在运行的代码,我尝试使用回调来接收成功或失败,然后在适当的时候更新我的本地SQLite DB。

- (void)postlowData:(NSArray *)lowMArray Callback:(void (^)(NSError *error, BOOL success))callback;
{
// Currently this method is sending the whole lowMArray
// What I want to do is Split lowMArray into a chunkArray (where chunk is 20 of the leading items from lowMArray)
// I would then send chunkArray with the following code, when I receive a response I then want to update local SQLite DB with result and recall this method to start on the next 20 chunks.
        // Create Json data from lowMArray
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:lowMArray
                                                           options:NSJSONWritingPrettyPrinted
                                                             error:nil];

        // Construct post request
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/lows", _silServerBaseUrl]]];
        request = [self applyAuth:request];
        [request setHTTPMethod:@"POST"];
        [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
        [request setHTTPBody:jsonData];

        // Send post request
        AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
        NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
            if (error) {
//                NSLog(@"Response Failed!");
                callback(error, NO);
            } else {
//                NSLog(@"Response Success!");
                callback(error, YES);
                // On success add itmes from lowChunkArray so that you can adjust sent_Flag later
            }
        }];
        [dataTask resume]; // runs task
}

我遇到的问题是,当我运行此代码时,如果我将数组拆分为块,发送块调整主数组以用于下一个块我不会得到确认的回调,直到所有的结尾请求,此时我已经忘记了成功或失败的原因?

也许我会以错误的方式解决这个问题?

更新

我现在正尝试使用AFHTTPRequestOperation执行此操作,这似乎是作为批量上传工作但是

  

setHTTPBody:jsonData

似乎永远不会进入服务器。

我使用这个Batch of Operations example来帮助我构建这个方法,但正如我上面所说的那样,JSON数据永远不会进入服务器。

- (void)postlowData:(NSArray *)lowMArray;
{
    NSLog(@"Syncing Local");

    NSArray *chunklow = [[NSArray alloc] init];
    NSMutableArray *mutableOperations = [NSMutableArray array];

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/lows", _silServerBaseUrl]];

//Test: creating 10 things to send 
        for (int i = 0; i < 10; i++) {
            if ([lowMArray count] > 0) {
                if ([lowMArray count] >= 20) {
                    low = [lowMArray subarrayWithRange:NSMakeRange(0, 20)];
                } else if ([lowMArray count] < 20) {
                    low = [lowMArray subarrayWithRange:NSMakeRange(0, [lowMArray count])];
                }
            }

        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:low
                                                           options:NSJSONWritingPrettyPrinted
                                                             error:nil];

        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        request = [self applyAuth:request];
        [request setHTTPMethod:@"POST"];
        [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
        [request setHTTPBody:jsonData];

        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
        [mutableOperations addObject:operation];
    }

    NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:mutableOperations progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
        NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);
    } completionBlock:^(NSArray *operations) {
        NSLog(@"All operations in batch complete");
        NSLog(@"Syncing complete");
    }];
    [[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];

}

1 个答案:

答案 0 :(得分:0)

对于将大型数组插入到通过网络操作插入数据库的块的问题,可以创建NSOperationQueue,允许您为每个数据块添加单独的操作插入。

可以将队列设置为以串行方式运行,以便在下一个操作开始之前完成每个操作。

使用队列可以使多个操作比回调控制流更易于管理。

总之,您创建一个队列并将其最大并发操作数设置为1.然后创建一个NSOperation子类,该子类执行将数据插入数据库的必要步骤。每个数据块将对应于将添加到队列的单独操作。每个操作都将按顺序执行,直到完成所有操作。

以下是解决方案的大纲:

// Create a new queue to hold network operations.
self.operationQueue = [[NSOperationQueue alloc] init];
self.operationQueue.maxConcurrentOperationCount = 1;

// Split the large array into chunks of 20 items each.
NSInteger chunkSize = 20;

NSInteger i = 0;
NSInteger total = [lowMArray count];

while (i < total) {    
    NSInteger j = i;
    NSMutableArray *chunk = [NSMutableArray alloc] init];
    while (j < i + chunkSize - 1 && j < total)  {
        [chunk addObject:lowMArray[j]];
        j++;
    }

    MyOperation *myOperation = [[MyOperation alloc] initWithArray:chunk];        
    self.operationQueue.addOperation(myOperation)

    i += chunkSize;
}    

MyOperation.h:

@interface MyOperation : NSOperation

- (instancetype)initWithArray:(NSArray *)chunk;
@property NSArray *chunk;

@end

MyOperation.m:

@implementation MyOperation

- (instancetype)initWithArray:(NSArray *)chunk
{
    if (self = [super init]) {
        self.chunk = chunk;
    }
    return self;
}

- (void)main
{
    // Create Json data from lowMArray
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:self.chunk
                                                       options:NSJSONWritingPrettyPrinted
                                                         error:nil];

    // Construct post request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/lows", _silServerBaseUrl]]];
    request = [self applyAuth:request];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json; charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:jsonData];

     // Send post request
     AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
     NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {

        if (error) {
            // NSLog(@"Response Failed!");
        } else {
            // NSLog(@"Response Success!");
        }
    }];

    [dataTask resume]; // runs task
}

@end

AFNetworking在NSOperation中支持自己的AFHTTPRequestOperation子类。可以找到一个示例here。此外,AFNetworking GitHub存储库有example for batch operations

根据您修改过的问题,设置每个AFHTTPRequestOperation的完成块以处理响应和错误可以帮助调试问题。

以下是如何完成的:

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation * _Nonnull operation, id  _Nonnull responseObject) {
    NSString* decodedResponse = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    NSLog(@"response %@", decodedResponse);
} failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) {
    NSLog(@"error %@", error);
}];

它将在AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];之后插入。