简体   繁体   中英

Why does NSBundle mainBundle work, but not documentsDirectory?

I am trying to to make a connection to a database and I'm finding that it is successful when I make the path go to NSBundle, but not when I try make the path be in my app's documents directory. Here is my code:

-(IBAction)setInput:(id)sender
{
    NSString *strStoreNumber;
    NSString *strRegNumber;

    strStoreNumber = StoreNumber.text;
    strRegNumber = RegNumber.text;

    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString* documentsDirectory = [paths lastObject];
    NSString* databasePath = [documentsDirectory stringByAppendingPathComponent:@"tblStore.sqlite"];
//    NSString* databasePath = [[NSBundle mainBundle] pathForResource:@"tblStore" ofType:@"sqlite"];

    if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) 
    {
        NSLog(@"Opened sqlite database at %@", databasePath);
        sqlite3_exec(database, "CREATE TABLE IF NOT EXISTS tblStore (ID INTEGER PRIMARY KEY AUTOINCREMENT, Message TEXT)", NULL, NULL, NULL);
        //...stuff
    } 
    else 
    {
        NSLog(@"Failed to open database at %@ with error %s", databasePath, sqlite3_errmsg(database));
        sqlite3_close (database);
    }
//    
    NSString *querystring;

    // create your statement
    querystring = [NSString stringWithFormat:@"SELECT strStore, strReg FROM tblStore WHERE strStore = %@ AND strReg = %@;", strStoreNumber, strRegNumber];  

    const char *sql = [querystring UTF8String];

    NSString *szStore = nil;
    NSString *szReg = nil;

    sqlite3_stmt *statement = nil;
    if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL)!=SQLITE_OK) //queryString = Statement
    {
        NSLog(@"sql problem occured with: %s", sql);
        NSLog(@"%s", sqlite3_errmsg(database));
    }
    else
    {
        // you could handle multiple rows here
        while (sqlite3_step(statement) == SQLITE_ROW) 
        {            
            szStore = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 0)];
            szReg = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 1)];
        }        

    }

    sqlite3_finalize(statement);

    lblStoreNumber.text = szStore;
    lblRegNumber.text = szReg; 
//   
}

I commented out the line:

NSString* databasePath = [[NSBundle mainBundle] pathForResource:@"tblStore" ofType:@"sqlite"];

When this line is NOT commented out, and the lines above it ARE commented out:

NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString* documentsDirectory = [paths lastObject];

NSString* databasePath = [documentsDirectory stringByAppendingPathComponent:@"tblStore.sqlite"];

Then it works fine. However, if those three lines are not commented out (as shown in the setInput method, then I get the following errors:

2012-05-07 13:44:29.511 CCoDBTry[1981:f803] Opened sqlite database at    /Users/Matt****/Library/Application Support/iPhone Simulator/5.1/Applications/5DB7A218-A0F6-  485F-B366-91FD2F9BC062/Documents/tblStore.sqlite
2012-05-07 13:44:29.545 CCoDBTry[1981:f803] sql problem occured with: SELECT strStore, strReg FROM tblStore WHERE strStore = 8053 AND strReg = 4;
2012-05-07 13:44:29.546 CCoDBTry[1981:f803] no such column: strStore

Keep in mind, this same database table is accessed and works just fine when I use the NSBundle logic. I admit I don't fully understand the difference between NSBundle and documentsDirectory, but I think I would want my table to exist in my app's documents. I would greatly appreciate any help on this.

Thanks!

NSBundle is used to access resources within your application itself: that is, everything inside YourApp.app. The documentsDirectory is a location outside of your app -- it's in the "home directory" which is part of your app sandbox, and which is analogous to your user home directory on the Mac.

These are different locations, so using one to find a file at the same subpath of another won't work.

What @rickster is saying is this:

  1. If you add the sqlite database to your project in Xcode, the database's file gets added to your app's bundle.
  2. If you create the database in code, the file will (most likely) get created in your documents directory (but surely not in your bundle).
  3. The two locations are completely separate. Your bundle is created when your app is compiled and cannot be changed later. Your documents directory is "sandboxed", which allows you access to it; you can read/write/delete files here.

Copy from NSBUndle TO NSDocumentDirectory

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                     NSUserDomainMask,
                                                     YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"culinary-Info.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:path])
{
    NSString *bundle = [[NSBundle mainBundle] pathForResource:@"culinary-Info" ofType:@"sqlite"];
    [fileManager copyItemAtPath:bundle toPath:path error:nil];
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM