Сохранить ответ NSURLSessionDataTask для базы данных SQLite?

Мой код звонков HTTP отправить вызов на удаленный сервер и получить результаты в JSON формат, я извлек этот JSON, но теперь мне нужно сохранить эти результаты в SQLite. Основываясь на моем чтении NSURLSessionDataTask это фоновый поток, так что моя путаница заключается в том, должен ли я вызвать SQL открыть и вставить внутрь completionHandler (или) есть ли другая лучшая практика для обработки этого типа требований?

РЕДАКТИРОВАТЬ 1

Дело в том, что я больше борюсь за то, является ли допустимым писать операции SQLite внутри "ручки завершения "? будет ли "completeHandler" рассматриваться как метод в отдельном потоке (который выполняет SessionDataTask) или в основном потоке?

РЕДАКТИРОВАТЬ 2

Я открыт для решений, связанных с CoreData.

Любая помощь будет оценена.

NSURL *loginUrl = [NSURL URLWithString:@"myurl"];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:loginUrl];
request.HTTPMethod = @"POST";
NSString *ipData = [NSString stringWithFormat:@"uName=%@&pwd=%@",self.userName.text,self.userPwd.text];
request.HTTPBody = [ipData dataUsingEncoding:NSUTF8StringEncoding];


NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *jsonError) {
    NSLog(@"Inside post data task......");

    NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
    if(httpResp.statusCode == 200)
    {
        NSLog(@"Response succesfull.........");
        NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];

        if(!jsonError)
        {
            //No Json error
            NSString *uName = jsonDict[@"userName"];
            NSString *uID = jsonDict[@"uID"];
            //HOW CAN I INSERT THESE DETAILS TO SQLITE DB BEFORE CALLING SEGUE TO MOVE TO NEXT SCREEN?
            dispatch_async(dispatch_get_main_queue(), ^{
                  [self performSegueWithIdentifier:@"mysegueID" sender:self];
                });
            }
    }else
    {
        NSLog(@"Response is not succesfulll...");
    }
}];

[postDataTask resume];

2 ответа

Решение

Многие люди используют FMDB как обёртку для target -c вокруг sqlite.

В случае NSURLSession блок обработчика завершения будет выполняться в "очереди делегатов" (см. Свойство DelegateQueue NSURLSession).

Допустимо использовать SQLite в обработчике завершения, если вы следуете правилам потоков SQLite. Я рекомендую ее снова лечить, потому что у нее есть помощники для этого. Смотрите Использование FMDatabaseQueue и Thread Safety.

Итак, ваш пример будет выглядеть так:

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];

NSURL *loginUrl = [NSURL URLWithString:@"myurl"];
NSURLSession *session = [NSURLSession sharedSession];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:loginUrl];
request.HTTPMethod = @"POST";
NSString *ipData = [NSString stringWithFormat:@"uName=%@&pwd=%@",self.userName.text,self.userPwd.text];
request.HTTPBody = [ipData dataUsingEncoding:NSUTF8StringEncoding];


NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *jsonError) {
    NSLog(@"Inside post data task......");

    NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
    if(httpResp.statusCode == 200)
    {
        NSLog(@"Response succesfull.........");
        NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];

        if(!jsonError)
        {
            //No Json error
            NSString *uName = jsonDict[@"userName"];
            NSString *uID = jsonDict[@"uID"];
            //HOW CAN I INSERT THESE DETAILS TO SQLITE DB BEFORE CALLING SEGUE TO MOVE TO NEXT SCREEN?
            [queue inDatabase:^(FMDatabase *db) {
                  NSDictionary *argsDict = @{ @"uName" : uName, @"uID" : uID};
                  [db executeUpdate:@"INSERT INTO myTable (name) VALUES (:name)" withParameterDictionary:argsDict];
            }];

            dispatch_async(dispatch_get_main_queue(), ^{
                  [self performSegueWithIdentifier:@"mysegueID" sender:self];
                });
            }
    }
    else
    {
        NSLog(@"Response is not succesfulll...");
    }
}];

[postDataTask resume];

БД SQLite может быть доступна из любого потока в приложении. Единственное ограничение заключается в том, что SQLite недопустимо допускает одновременный доступ из нескольких потоков (и "одновременный" здесь применяется к продолжительности "транзакции", а не просто к продолжительности вызова методов SQLite).

Таким образом, вы должны как-то заверить, что никогда не будет одновременного доступа. Простой способ сделать это - всегда использовать один и тот же поток (например, основной поток) для доступа. Или вы можете реализовать "мягкие" протоколы так, чтобы вы знали, что два действия не пытаются одновременно использовать БД, потому что они разделены во времени. Или вы можете использовать блокировку Objective-C или другие механизмы синхронизации в программном обеспечении / ОС.

Другие вопросы по тегам