我有一个很大的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];
}
答案 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];
之后插入。