I have a problem with a sqlite project that i'm doing, I'm using FMDB, I follow a simple example, but doesn´t work. And I can't find the error. I did my database schema from the terminal, I put some data on it. I'm very new to ios dev, so I don't know exactly if I did the steps ok.
This is what I did:
1 - I made my Database schema and add some fields. 2 - I copied the database.db into my project folder in xcode. 3 - I add the FMDB files. 4 - I add the sqlite3.dylib 5 - I put this code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.dbname = #"database.db";
NSArray * docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * docDIr = [docPath objectAtIndex:0];
self.dbpath = [docDIr stringByAppendingPathComponent:dbname];
[self checkDB];
[self getQ];
return YES;
}
-(void) getQ
{
FMDatabase * db = [FMDatabase databaseWithPath:dbpath];
[db open];
FMResultSet * result = [db executeQuery:#"SELECT * FROM table1"];
NSLog(#"last Error: %#",[db lastErrorMessage]);
NSLog(#"result: %#", result);
}
-(void) checkDB
{
BOOL success;
NSFileManager * fm = [NSFileManager defaultManager];
success = [fm fileExistsAtPath:dbpath];
NSError * error = [[NSError alloc] init];
if (success) return;
NSLog(#"result:");
NSString * dbPathFromApp = [[[NSBundle mainBundle] resourcePath]stringByAppendingPathComponent:self.dbname];
[fm copyItemAtPath:dbPathFromApp toPath:dbpath error:&error];
}
Apparently the database it's empty, so what happened? why I can't find table1 ? If I open the file with any sqlite gui, the table appears just fine. Thank's for any help
The console show me the next lines:
2013-03-02 14:03:31.839 myApp[21433:c07] last Error: no such table: table1
2013-03-02 14:03:31.841 myApp[21433:c07] result: (null)
A couple of thoughts:
I'd confirm the database has been added to your bundle. Go to your target settings, select "Build Phases", expand "Copy Bundle Resources", and make sure your database is listed there. If not, click on the "+" button and add it.
I'd reset your simulator. If you ever ran the app and didn't copy the database properly, it would have created a blank database for you in your documents folder. By resetting your simulator, you can get rid of any blank databases that might be there.
If it's still not working, I'd check the bundle database in your simulator. Navigate to the simulator folder (~/Library/Application Support/iPhone Simulator), find the app, open up the bundle (by control clicking on the app itself and say "show package contents"), and check the database in there and make sure it has your table1.
After adding the Database file please select that and Tick Mark Target Membership.
Related
I have an iOS app that uses sqlite, the sqlite database file is preconfigured and added in xcode. Everything works great until I need to add a new table named "activities" in this sqlite file, so I added the table for the database file, replaced the database file in xcode, and now while running on either simulator or real iOS device, it keeps complaing "no such table: activities". Even if I delete the previously installed app on my device or simulator doesn't work. What is happening there? By the way, below is the code I deal with the database file everytime I instantiate my DatabaseManager:
- (instancetype)initWithDatabaseFilename:(NSString *)dbFilename {
self = [super init];
if (self) {
// Set the documents directory path to the documentsDirectory property.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
self.documentsDirectory = [paths objectAtIndex:0];
// Keep the database filename.
self.databaseFilename = dbFilename;
// Copy the database file into the documents directory if necessary.
[self copyDatabaseIntoDocumentsDirectory];
}
return self;
}
- (void)copyDatabaseIntoDocumentsDirectory {
// Check if the database file exists in the documents directory.
NSString *destinationPath = [self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename];
if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
NSLog(#"file not exists");
// The database file does not exist in the documents directory, so copy it from the main bundle now.
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseFilename];
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:destinationPath error:&error];
// Check if any error occurred during copying and display it.
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
} else {
NSLog(#"file is already there");
}
}
Delete database file from document directory through terminal path generated in copyDatabaseIntoDocumentsDirectory method drag and drop database file in project.make sure tables are created through terminal.
I'm running Xcode 6 Beta 5 but this has been happening since the first beta. My app's directory in the simulator keeps being renamed after each run. It took me a while to figure this out. I'm using this to get the doc's dir reference.
NSString *folder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES) lastObject];
NSLog(#"Documents Dir: %#",folder);
Now for example on the first run it'll be:
/Users/Joey/Library/Developer/CoreSimulator/Devices/5B9930EE-A9B4-4B36-BABB-AA864ACAF2DE/data/Containers/Data/Application/4B10C2E4-A5C3-4C64-93B1-4069FCCB9C46/Documents
Second run now it's:
/Users/Joey/Library/Developer/CoreSimulator/Devices/5B9930EE-A9B4-4B36-BABB-AA864ACAF2DE/data/Containers/Data/Application/7E9EB62D-115A-4092-AD23-CB6BA3E5E10F/Documents
Third run:
/Users/Joey/Library/Developer/CoreSimulator/Devices/5B9930EE-A9B4-4B36-BABB-AA864ACAF2DE/data/Containers/Data/Application/EC8F41E8-52ED-4B10-9808-B3ACC46FC6AA/Documents
This is wreaking havoc with my app because it stores path references for certain files within the app. It's not that my NSLog statement is returning incorrect results, I verified this is what happening in Finder. It's changing the name every time. Has anyone seen this happen? Is this a "feature" that I'm misunderstanding?
Turns out Xcode 6 does in fact change the app's UUID every run, and I'm in the wrong for storing absolute paths.
USE SIMPHOLDERS
I used this app on Xcode 5 opens the Documents folder, for the currently running app in the simulator, in Finder.
http://simpholders.com/
not ready for Xcode 6 yet (as of sep 24 2014) but saves all this hassle.
In Xcode 6 / iOS8 The bundle is now separate from the data./ The application GUID is regenerated between runs in Xcode (not sure why)
DOCUMENTS DIR:/Users/gbxc/Library/Developer/CoreSimulator/Devices/AC79941F-EC56-495E-A077-773EEE882732/data/Containers/Data/Application/C220D351-0BE7-46BA-B35E-D16646C61A3F/Documents
mainBundlePath_:/Users/gbxc/Library/Developer/CoreSimulator/Devices/AC79941F-EC56-495E-A077-773EEE882732/data/Containers/Bundle/Application/12200D1D-9B67-408B-BCF7-38206CBE0940/myappname.app/BLANK_BLOG_SCALED.jpg
1. FIND THE DEVICES FOLDER in SIMULATOR
/Users/gbxc/Library/Developer/CoreSimulator/Devices/
open each /device.plist to see which GUID is which device in XCode - I think this is static
3. FIND THE DEVICE you're running on iPad 2 - I think this is static
/Devices/AC79941F-EC56-495E-A077-773EEE882732
4. Find your application /Documents folder
/AC79941F-EC56-495E-A077-773EEE882732/data/Containers/Data/Application/C220D351-0BE7-46BA-B35E-D16646C61A3F/Documents
BEWARE the GUID C220D351-0BE7-46BA-B35E-D16646C61A3F is regenerated everytime the app is run in XCode 6
NSArray *paths_ = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
if(paths_){
_docsDir = [paths_ firstObject];
DebugLog(#"DOCUMENTS DIR:%#",_docsDir);
}else{
ErrorLog(#"paths_ is nil - cant get Documents directory");
}
MAIN BUNDLE path
NSString *mainBundlePath_ = [[NSBundle mainBundle] pathForResource:#"someimageinyourbundle" ofType:#"jpg"];
/AC79941F-EC56-495E-A077-773EEE882732/data/Containers/Bundle/Application/12200D1D-9B67-408B-BCF7-38206CBE0940/clarksonsiq.app/BLANK_BLOG_SCALED.jpg
NEVER CACHE THE PATH to /Documents between runs it will change.
I was serializing it to a plist and couldnt figure out why they kept disappearing
The GUID above /Documents keeps changing between runs but if you have /Documents open in Finder the folder stays open.
https://devforums.apple.com/thread/235911?tstart=0
https://devforums.apple.com/thread/238754?tstart=0
Free Solution
Use Open Source Library OpenSim. OpenSim is an open source alternative for SimPholders, written in Swift.
Paid Solution
Use SimPholder application to know current application location.
For xcode 6.0 >
Download SimPholder 2.0 alpha 2
For xcode 5.1 <
Download SimPholders 1.5
I can confirm that this is Xcode 6 related not iOS 8.
I have two development machines. On one of them I have Xcode 5. I was working all the time on that machine and my URL's were fine (photo app, photos are visible).
Yesterday I checked in form git my source on a machine with Xcode 6. I noticed that my photos are not visible any more, only photos that are created during that app session.
After little debugging, I realized that file:///var/mobile/Applications/B6A6BAEF-C90C-4A2A-93DB-E6700B88971F/Documents/ is changing on every app run.
All that time I am working with iOS 7 device.
I am going to check once more on a machine with Xcode 5 to confirm when I get my hands on it.
You need to to save only path inside DocumentDirectory(directory/file name), and add it to the DocumentDirectory every time you load the file...
-(void)saveImage:(UIImage *)image{
NSData *pngData = UIImagePNGRepresentation(image);
NSString *pathInDocumentDirectory = [APP_DocumentDirectory stringByAppendingPathComponent:PROFILE_IMAGE_NAME];
NSString *filePath = [self documentsPathForFileName:pathInDocumentDirectory];
//Save pic file path - DirName/Filename.png
[XYZPreferencesHelper setUserImageFilePath:pathInDocumentDirectory];
//Write the file
[[NSFileManager defaultManager] createFileAtPath:filePath contents:pngData attributes:nil];
}
-(void)loadSavedUserPicture{
//Load saved DirName/Filename.png
NSString *pathInDocumentDirectory = [XYZPreferencesHelper getUserImageFilePath];
if (pathInDocumentDirectory != nil){
//Full path with new app Document Directory
NSString *filePath = [self documentsPathForFileName:pathInDocumentDirectory];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]){
NSData *pngData = [NSData dataWithContentsOfFile:filePath];
UIImage *image = [UIImage imageWithData:pngData];
if (image != nil){
userPicImageView.image = image;
}
}
}
}
- (NSString *)documentsPathForFileName:(NSString *)name
{
NSString *documentsPath = [self createRestcallDirectoryIfNotExist];
return [documentsPath stringByAppendingPathComponent:name];
}
-(NSString *)createRestcallDirectoryIfNotExist{
NSString *path;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
path = [documentsPath stringByAppendingPathComponent:APP_DocumentDirectory];
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) //Does directory already exist?
{
if (![[NSFileManager defaultManager] createDirectoryAtPath:path
withIntermediateDirectories:NO
attributes:nil
error:&error])
{
NSLog(#"Create directory error: %#", error);
}
}
return documentsPath;
}
Because app's UUID changes and not reliable
so we should not store urls instead we should store just file names and reconstruct url at runtime , on update/reinstall iOS creates new home directory, stores app bundle in it and copies documents files so url changes
Here's what I need: To have a sqlite file populated with example entities that I made on the iPhone simulator, and then copy that file when the app initially runs for all my users.
What I've done:
I created a bunch of entries within the simulator.
I found the sqlite file attached to my app within the iPhone Simulator iOS folder on the MAC.
From the three files, .sqlite, .sqlite-shm, .sqlite-wal I simply copied the .sqlite file to my xCode project.
When I ran the app, the .sqlite file showed up empty!
How do I fix this?
Thank you!
EDIT:
What significance does the .sqlite-wal and .sqlite-shm have?
Why do they exist and why did not exist prior to iOS7?
first steps R OK but then U have to load the database
U need smth like this:
- (void)copyPreparedDatabase{
__persistentStoreCoordinator = nil;
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"DATABASE.sqlite"];
NSString *storePath = [storeURL path];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"DATABASE" ofType:#"sqlite"];
if (defaultStorePath) {
NSError *error = nil;
if ([fileManager fileExistsAtPath:storePath]) {
[fileManager removeItemAtPath:storePath error:&error];
}
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:&error];
NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:storePath error:&error]) {
}
}
}
And then U call it from - (NSPersistentStoreCoordinator *)persistentStoreCoordinator from
AppDelelate.m
Advice: Do some custom switch like
#define IMPORT_PREPARED_DATABASE
do it like this:
if (![fileManager fileExistsAtPath:storePath] && !IMPORT_PREPARED_DATABASE) { //&& 1==2
[self copyPreparedDatabase];
}
so U can control when to build new prepared database or when to use existing one....
Note:
When U build new prepared database sto simulator, copy database and paste it over the old one...
This tutorial can be a big help.
You made almost everything, but you are missing an important step. You need to copy the sqlite to your xcode project then you need to check in your persistentStoreCoordinator if the sqlite file exists in your Documents area. If not, you need to copy it. Jump to "Doctor, you’re needed in Xcode" section in that tutorial :).
I want to use a pre populated database with my web-app, so that my app works offline. How can i do this with the newest version of PhoneGap / Cordova (2.0)?
I know that this question has been asked before, but all answers seem to be out of date relative to the current version of cordova and iOS
https://github.com/atkinson/phonegap-prepopulate-db has not been updated for two years
https://github.com/davibe/Phonegap-SQLitePlugin has not been updated for 7 months and is for 1.7
I found a post here:
http://www.raymondcamden.com/index.cfm/2012/7/27/Guest-Blog-Post-Shipping-a-populated-SQLite-DB-with-PhoneGap is this the only way?
Also, i should note that i use iOS 6
I have used the following plugin for Cordova 2.7 with iOS6 and I see it was just updated a day ago. https://github.com/pgsqlite/PG-SQLitePlugin-iOS
They also have an Android version here as well.
Part of the problem is PhoneGap changes so often keeping plugins up to date can be time consuming so they lapse. Here is the code for the init method in the AppDelegate.m I use in this project http://www.binpress.com/app/conference-core-ios-for-phonegap/1483
Keep in mind that you sometimes need to wipe the iOS Simulator so it reloads the files related to the application.
- (id)init{
NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
if __has_feature(objc_arc)
NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:#"nsurlcache"];
else
NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:#"nsurlcache"] autorelease];
endif
[NSURLCache setSharedURLCache:sharedCache];
databaseName = #"SomeCoolDatabase.db";
NSLog(#"databaseName: %#", databaseName);
databasePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex: 0];
NSLog(#"databasePath: %#", databasePath);
databaseFile = [databasePath stringByAppendingPathComponent:databaseName];
NSLog(#"databaseFile: %#", databaseFile);
// Execute the "checkAndCreateDatabase" function
[self checkAndCreateDatabase];
self = [super init];
return self;
}
-(void)checkAndCreateDatabase {
// Check if the SQL database has already been saved to the users phone, if not then copy it over
BOOL success;
// Create a FileManager object, we will use this to check the status
// of the database and to copy it over if required
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databaseFile];
// If the database already exists then return without doing anything
if(success){
NSLog(#"Database Present");
return;
} else {
NSLog(#"database not present");
}
// If not then proceed to copy the database from the application to the users filesystem
// Get the path to the database in the application package
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Create the database folder structure
[fileManager createDirectoryAtPath:databasePath withIntermediateDirectories:YES attributes:nil error:NULL];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databaseFile error:nil];
[fileManager release];
}
Hope this helps...
Thank you! I wouldn't have been able to do this without starting here!
That said, this wasn't working for me out of the box, so I updated it, and I'm by no means 'good' with native code for iOS, so I'm VERY open to suggestions.
I added the suggested code to the AppDelegate.m file, got a heap of errors.
So, I moved over to the AppDelegate.h file:
#interface AppDelegate : NSObject <UIApplicationDelegate>{} --Looks like this to start.
Make it look like this:
#interface AppDelegate : NSObject <UIApplicationDelegate>{
NSString* databaseName;
NSString* databasePath;
NSString* databaseFile;
}
I just had to declare the variables in there.
I also removed this line:
[fileManager release];
As, according to this answer, my project seemingly automatically releases? I hope?
Now I have to work on getting the DB file into the correct location for xcode to find it.
Hope this helps!
Though this question is old... thought it might help someone to post my solution - found in 2017. (Since PhoneGap has changed, older solutions no longer will work or be accepted on the Android and Apple app markets.) I worked on this problem for a long time - the issue is you want to import a pre-populated database - which there are not alot of easy solutions for. I found the best and easiest - and currently just about the ONLY - solution to be LiteHelpers CORDOVA-SQLITE-EXT (https://github.com/litehelpers/cordova-sqlite-ext)
I have added this in to my app and it is working well. I had to switch away from PhoneGap though - and use CORDOVA - but it is working for me.
I have a weird problem. My app works fine on my device but the sqlite database does not work on the simulator. The file "database.sqlite" exists in the same folder as my apps, it has the same name and the columns names are also correct.
So I assume there is something wrong with the configuration but I don't know what. Can someone please help me out.
Thanks
Here are some posts that seem to address the problem : http://forums.macrumors.com/showthread.php?t=484899
One reason might be because you should ensure the database is copied from your Supporting Files application directory (read only) to library or documents before you use it. Here's an ensurePrepared function from a sample of mine that uses sqlite that does just that. In this case, it's called contacts.db
- (BOOL)ensureDatabasePrepared: (NSError **)error
{
// already prepared
if ((_dbPath != nil) &&
([[NSFileManager defaultManager] fileExistsAtPath:_dbPath]))
{
return YES;
}
// db in main bundle - cant edit. copy to library if !exist
NSString *dbTemplatePath = [[NSBundle mainBundle] pathForResource:#"contacts" ofType:#"db"];
NSLog(#"%#", dbTemplatePath);
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
_dbPath = [libraryPath stringByAppendingPathComponent:#"contacts.db"];
NSLog(#"dbPath: %#", _dbPath);
// copy db from template to library
if (![[NSFileManager defaultManager] fileExistsAtPath:_dbPath])
{
NSLog(#"db not exists");
NSError *error = nil;
if (![[NSFileManager defaultManager] copyItemAtPath:dbTemplatePath toPath:_dbPath error:&error])
{
return NO;
}
NSLog(#"copied");
}
return YES;
}