0

My code calls HTTP post call to remote server and obtains results in JSON format, I have extracted this JSON, but now I need to store these results to SQLite. Based on my reading NSURLSessionDataTask is background thread, so my confusion is, should I call SQL open and insert inside completionHandler (or) is there any other best practice to handle this type of requirements?

EDIT 1

The point I am struggling more is, is it valid to write SQLite operations inside "completionHandler"? does "completionHandler" will be considered as method on separate thread (which is executing SessionDataTask) or main thread?

EDIT 2

I am open to CoreData related solutions too.

Any help would be appreciated.

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];
kosa
  • 63,683
  • 12
  • 118
  • 157
  • Just to clarify, direct SQL and not CoreData is what you want, right? (And as an aside, why?) – RobP Dec 11 '14 at 16:41
  • Thanks for your question! 1) I am new to iOS dev (from Android background), so SQL query for SQLite is easier for me. 2) My app is not SQLite intensive, in other words, only one time insert data, remaining time read only. Hope it make sense. – kosa Dec 11 '14 at 16:51
  • CoreData does have some advantages, for sure, even for simple SQL usage. I found this link helpful to explain why. Migrating to future schema versions is one example of what it handles well for you. http://sealedabstract.com/code/you-should-use-core-data/ – RobP Dec 11 '14 at 17:06
  • Thank you for that @RobP I will look into. My data model is not complex one, so switching to core data is not a big issue for me. Feel free to answer this question if have solution with core data. – kosa Dec 11 '14 at 17:17

2 Answers2

1

A lot of people use FMDB as objective-c wrapper around sqlite.

In case of NSURLSession, the block of the completion handler will be executed on the "delegate queue" (see delegateQueue property of NSURLSession).

It is valid to do SQLite in completion handler as long as you follow SQLite threading rules. I recommend FMDB her again because it has helpers for this. See Using FMDatabaseQueue and Thread Safety.

So your example would look like:

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];
catlan
  • 23,677
  • 8
  • 64
  • 74
  • Thanks for the answer! The point I am struggling more is, is it valid to write SQLite operations (using raw SQL (or) any framework) inside "completionHandler"? does "completionHandler" will be considered as separate thread (which is executing SessionDataTask) or main thread? Could you please help with these questions too? – kosa Dec 11 '14 at 17:20
  • Ok. Got it. Thank you! – kosa Dec 12 '14 at 05:05
1

A SQLite DB can be accessed from any thread in an app. The only restriction is that SQLite does not happily tolerate simultaneous access from multiple threads (and "simultaneous" here applies to the duration of a "transaction", not simply the duration of a call to SQLite methods).

So you must somehow assure that there is never simultaneous access. A simple way to do this is to always use the same thread (eg, the main thread) for access. Or you can implement "soft" protocols such that you know that two actions are not simultaneously trying to use the DB because they are separated in time. Or you can make use of Objective-C lock or other synchronization mechanisms in the software/OS.

Hot Licks
  • 44,830
  • 15
  • 88
  • 146