0

I am using SQLite via FMDB in my app, and it's been working for the past couple months on all the XCode simulators, however, when I am now testing on an actual device, I seem to be getting problems when I try to insert.

The error I'm getting is:

error domain = fmdatabase code=14 "unable to open database file" UserInfo = 0x178665340 {NSLocalizedDescription=unable to open database file}

Here's my code:

I have all of my FMDB stuff wrapped in a Helper Class I created:

_lHelper = [[BTRLocationsDatabaseHelper alloc] init];
    self.dbString = [_lHelper checkTableAndCreate:TABLE_LOCAL_LOCATIONS];

That calls:

  NSString *const LOCATIONS_DB_PATH = @"/Library/Caches/myapp_locations.db";
  NSString *const TABLE_LOCAL_LOCATIONS = @"locallocations";
 NSString *const TABLE_FAVORITE_LOCATIONS = @"favoritelocations";

  - (instancetype)init {
self = [super init];

if(self) {

    _db = [FMDatabase databaseWithPath:LOCATIONS_DB_PATH];

    if(![_db open]) {
        NSLog(@"Error opening myapp_locations database");
    }
}

return self;
}

-(NSString *)checkTableAndCreate:(NSString *)table {
NSString *errorString = @"";
FMResultSet *rs = [self.db executeQuery:@"select DISTINCT tbl_name from sqlite_master where tbl_name = ?", table];
[rs next];
BOOL errors = NO;
if([rs hasAnotherRow]) {
    // table exists - I think -> So here we would do nothing
    NSLog(@"locallocations table existed");
} else {
    NSLog(@"locallocations table does not exist");

    // table does not exist - I think -> So here we would create the table
    if([table isEqualToString:TABLE_LOCAL_LOCATIONS]) {
        NSLog(@"Creating a new locallocations table");
        BOOL success = [self.db executeUpdate:@"create table locallocations .....)"];

        if(!success) {
            errors = YES;
            NSString *err = [NSString stringWithFormat:@"%@", [self.db lastError]];
            [errorString stringByAppendingString:err];
            NSLog(@"Error create table locallocations: %@", [self.db lastError]);
        }
    }

}

FMResultSet *rsFavorites = [self.db executeQuery:@"select DISTINCT tbl_name from sqlite_master where tbl_name = ?", @"favoritelocations"];
[rsFavorites next];
BOOL errorsFavorites = NO;
if([rsFavorites hasAnotherRow]) {
    // table exists - I think -> So here we would do nothing
    NSLog(@"favoritelocations table existed");
} else {
    NSLog(@"favoritelocations table does not exist");
    NSLog(@"Creating a new favoritelocations table");
    // table does not exist - I think -> So here we would create the table
    BOOL success = [self.db executeUpdate:@"create table favoritelocations ...."];

    if(!success) {
        errorsFavorites = YES;
        NSString *err = [NSString stringWithFormat:@", %@", [self.db lastError]];
        [errorString stringByAppendingString:err];
        NSLog(@"Error create table favoritelocations: %@", [self.db lastError]);
    }
}


// Down here we would do logic for adding new columns if we ever need them - if errors is false

return errorString;
}

After that's done I print out errorString and it's empty so that makes me believe the table creation worked.

Then I later try to do an insert calling this method in the Helper Class:

  -(NSString *)insertFavoriteLocation:(BTRLocation *)location
                   userId:(int)userId {
NSMutableDictionary *dictionaryArgs = [NSMutableDictionary dictionary];
//... just adding stuff to my dictionary

BOOL result = [self.db executeUpdate:@"insert into favoritelocations ....];

NSError *error = [self.db lastError];
NSString *errorString = [NSString stringWithFormat:@"%@", error];
return errorString;

}

After that runs I print out errorString and it says the error I pasted above, error code 14 unable to open database file.

So this works perfectly on a Simulator, what could be causing this to not work on a device (iPhone 5s to be specific, but that's the only device I've tried).

Thanks!

EDIT:

    NSString* path = [NSSearchPathForDirectoriesInDomains(
                                                          NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];

Solution:

For those that care, this is how I ended up fixing it:

Modified the init method to have:

  NSString *cachePath = [NSSearchPathForDirectoriesInDomains(
                                                          NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *dbPath =  [cachePath stringByAppendingPathComponent:@"myapp_locations.db"];
    _db = [FMDatabase databaseWithPath:dbPath];
user1513171
  • 1,912
  • 6
  • 32
  • 54
  • 1
    You can't hardcode a non-existent path for the database file. Use proper code to get the path within your app's sandbox. – rmaddy Nov 02 '14 at 21:32
  • Could you explain what you mean, please. Also note, I added constants that I use. Not sure if you saw that edit. – user1513171 Nov 02 '14 at 21:33
  • 1
    Yes, I saw the constants. That's the problem. You can't hardcode the path like that. You need to determine the path at runtime since the path needs to be a valid path for your app's sandbox. – rmaddy Nov 02 '14 at 21:34
  • I'm not sure how to do that, could you point me towards something? I was experimenting with the code I just added at the bottom, but I'm not sure how to use that to get Library/caches/myDbFile.db – user1513171 Nov 02 '14 at 21:37
  • 1
    See https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010672-CH1-SW1 – rmaddy Nov 02 '14 at 21:40

0 Answers0