0

I am using the code below to create db in one class and using it in the viewController and same code again in another class in newViewController .
Is it correct ? Or does it create new db in its place or uses if there is an existing db ?

or Do I need to use only the path ?

When I tried extern NSString *path in the example below I received Chinese letters and could not open it.

Basically in the 2nd contoller I am only reading the data.
So I am trying to access db via path,database with path and database open.

How do it if I have used the code below to create it and I would like to open it 2nd time from another viewcontoller.
Please help.
Thanks in Advance.

In 1st Contoller:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:@"test.db"];

FMDatabase *database;
database = [FMDatabase databaseWithPath:path];
[database open];

    [database executeUpdate:@"DROP TABLE IF EXISTS **"];


    [database executeUpdate:@"CREATE  TABLE "];



    //Select query for single row
    FMResultSet *s = [database executeQuery:@"SELECT COUNT(*) FROM table"];
    if ([s next]) {
        int Count = [s intForColumnIndex:0];


    }

 //DO Something

[database close];

Above code is working perfectly in viewcontroller 1 .

Things I tried in view controller 2 .And it still did not work.

extern NSString *path;



    FMDatabase *database;
    database = [FMDatabase databaseWithPath:path];
    [database open];

I get an error here since the path is in What looks like Chinese language.

Error is EXC_BAD_ACCESS code .

Also tried global database by :

extern FMDatabase *database;

and using it as

[database open];

I still get the same error.

Finally it worked with the following code in the 2nd controller.
I just wanted to see if thats the right way to do it or can I use something as db open .

But I tried that and its not working.Also I am not using any error handler as I dont know how to do it in FMDB .
Thanks in Advance.

Please let me know if the following implementation is correct ? :

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
         NSString *docsPath = [paths objectAtIndex:0];
        NSString *newpath = [docsPath stringByAppendingPathComponent:@"test.db"];


          FMDatabase *database2 ;
         database2 = [FMDatabase databaseWithPath:newpath];

         [database2 open];

//DO Something

[database2 close];
Jacob Wood
  • 467
  • 9
  • 26
  • It does not create a new database when you open it in the other controller. So, there must be an issue in how you're opening/using in one or the other controller. You'd have to show us a little more code to diagnose the problem. Are you checking the return codes for all of your FMDB calls to make sure everything is running successfully? Eg. you'd generally have `if (![datatabase2 open]) { NSLog("Open failed: %@", [datatabase2 lastErrorMessage]); }` and `if (![database2 executeUpdate:sql]) { NSLog("Execute failed: %@", [datatabase2 lastErrorMessage]); }`, etc. – Rob Jan 15 '13 at 22:14
  • @Rob Thank You Sir.I have edited the code above to explain the code I am using and the flow .PLease let me know if you need anything else to understand where I might have made mistake/implementation of the code.Thank you again Sir for your time and effort. Also, I am not using the return codes for all the FMDB calls .As I dont know how to do it . – Jacob Wood Jan 16 '13 at 07:47

2 Answers2

2

As an example of how you should be checking for the success of the FMDB methods, here is an example:

#import "FMDatabase.h"
#import "FMDatabaseAdditions.h"

- (void)performDatabaseDemonstration
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];
    NSString *path = [docsPath stringByAppendingPathComponent:@"test.db"];

    // open db

    FMDatabase *database = [FMDatabase databaseWithPath:path];
    FMResultSet *rs;

    if ([database open])
    {
        // drop table

        if (![database executeUpdate:@"DROP TABLE IF EXISTS test"])
            NSLog(@"%s: drop error: %@", __FUNCTION__, [database lastErrorMessage]);

        // create table

        if (![database executeUpdate:@"CREATE TABLE test(col1 INTEGER, col2 TEXT)"])
            NSLog(@"%s: create error: %@", __FUNCTION__, [database lastErrorMessage]);

        // insert a row of data

        if (![database executeUpdate:@"INSERT INTO test VALUES(1, 'Rob')"])
            NSLog(@"%s: insert 1 error: %@", __FUNCTION__, [database lastErrorMessage]);

        // insert another row of data

        if (![database executeUpdate:@"INSERT INTO test VALUES(2, 'Rachel')"])
            NSLog(@"%s: insert 2 error: %@", __FUNCTION__, [database lastErrorMessage]);

        // Select query for single row

        if (!(rs = [database executeQuery:@"SELECT count(*) FROM test"]))
            NSLog(@"%s: select error: %@", __FUNCTION__, [database lastErrorMessage]);

        if ([rs next]) {
            int count = [rs intForColumnIndex:0];

            NSLog(@"%s: count = %d", __FUNCTION__, count);
        }

        [rs close];

        // if getting single value from single row, you can use FMDatabaseAdditions.h methods:

        NSInteger count2 = [database intForQuery:@"SELECT col1, col2 FROM test"];
        NSLog(@"%s: count2 = %d", __FUNCTION__, count2);

        // let's actually retrieve data

        if (!(rs = [database executeQuery:@"SELECT col1, col2 FROM test"]))
            NSLog(@"%s: select error: %@", __FUNCTION__, [database lastErrorMessage]);

        while ([rs next]) {
            NSLog(@"%s: col1 = %@; col2 = %@", __FUNCTION__, [rs objectForColumnIndex:0], [rs objectForColumnIndex:1]);
        }

        [rs close];

        //close

        [database close];
    }
    else
    {
        NSLog(@"%s: open error: %@", __FUNCTION__, [database lastErrorMessage]);
    }
}

In terms of how to open a database from different controllers there are a ton of options. But I might suggest that above and beyond just retrieving some shared path/filename variable from two controllers, you might want to actually encapsulate not only the filename, but shared FMDB code, too, in an object.

Personally, whenever I find myself writing the same or similar code in two different controllers, I ask myself whether I want to abstract that code out into its own class. In this case, for example, rather than debating how these two classes access the database filename, I would create my own own model object (a NSObject subclass), that encapsulates your SQL, does the opening of the database, etc. Then I could have my two view controllers invoke the methods from that method object, and really minimize not only redundancy in the filenames, but in the code itself, too. For example, the creating of the database path, opening the database, checking the success of the open, etc., are identical. So why not have one method in some model object, that does all of that for you.

To make this model object accessible from both controllers, you have a bunch of options:

  • Make it a property of your first view controller, and have it pass it to your second controller during prepareForSegue;

  • Create a singleton object for it; or

  • Make that a property of your app delegate, and both of your controllers can get it from there.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thank you Sir . I have few queries : **NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docsPath = [paths objectAtIndex:0]; NSString *path = [docsPath stringByAppendingPathComponent:@"test.db"]; // open db FMDatabase *database = [FMDatabase databaseWithPath:path];** does this code create db if it does not exist but if does it uses it. Right ? Because thats how I am using in the code. – Jacob Wood Jan 16 '13 at 18:42
  • If Yes then I will make a method in the 1 st view controller for checking and creating db and call the same method from the 2nd controller right? – Jacob Wood Jan 16 '13 at 18:43
  • If the above mentioned is not correct please explain by writing code.Thank You. – Jacob Wood Jan 16 '13 at 18:58
  • Also Do I need to use **[rs close];** also as I used only **[db close];** till now .I guess that might be the error.What do you think? – Jacob Wood Jan 16 '13 at 20:41
  • @JacobWood We're going beyond the scope of the original question, so I'd suggest migrating this to chat: http://chat.stackoverflow.com/rooms/22871/fmdb-path-and-using-db-2nd-time-from-another-viewcontroller – Rob Jan 17 '13 at 03:23
0

You should put the database path defined as global variables, the first time to use the closing operation, the second use of time to open, open the database, it will automatically judge whether there are database, if there is no will automatically create.If present, it will directly open the. Used you to judge whether the database open success: if (! [db open]) { / / error return; } / / some operation / /... [db close];

jolenwood
  • 1
  • 1