I'm using XCode 6.4 and iOS Si,mulator iPhone 6. Every run of my app database or table is recreated so i lost all previously inserted data. I have 1 database with 1 table inside. Database file is located in Supporing Files directory of the project. Here is the code for database initialization:
BOOL success;
NSString *databasePath = [[NSBundle mainBundle] pathForResource:#"signals" ofType:#"sql"];
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:databasePath];
if (success) {
NSLog(#"exists");
return;
} else {
NSLog(#"No file found");
[fileManager copyItemAtPath:databasePath toPath:databasePath error:nil];
}
On run - success variable is YES - so i see in logs "exists". After that i insert one item to my table and do select query that returns this one inserted raw. On next run i should see two rows, but there is only one row again - so i assume the table was recreated. I need help with this problem.
Not got enough reputations to comment, but if you're not getting any No file found messages in your log, then I don't think this is the block of code that is causing the problem. Are you definitely doing an Insert query into the database and not an Update? Also, is your Select query returning all rows and not just one. Are you running through XCode or directly in the Simulator? XCode might overwrite the files if you're running it just through there - try re-running the app in the Simulator (CMD + Shift + H to get to the home screen), and seeing if that makes any difference.
This is not a bug in the simulator or in Xcode. There is a bug in your app and not in the simulator itself. You should not be modifying the database at this location:
[[NSBundle mainBundle] pathForResource:#"signals" ofType:#"sql"];
That is not persistent across updates of the application. You will see the same issue when updating your app on device.
Instead, use a persistent location, like:
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documents = [directories firstObject];
Related
I'm making an app that uses encoding to store objects on the document directory,
On iOS Simulator, the objects are getting saved perfectly, and if i closed the app and got back to it all the data are restored with no issue.
But today i tried my app on the iPhone 5s, the objects are not getting saved when i close the app and go back to it again all the data are getting removed only on the real device, what is the problem ?
I'm using this method to get the directory path:
- (NSString *)pathForTask
{
NSArray *documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [documentDirectories firstObject];
return [documentDirectory stringByAppendingString:#"Tasks"];
}
Archive:
NSString *path = [self pathForTask];
[NSKeyedArchiver archiveRootObject:self.privateTasks toFile:path];
Unarchive:
NSString *path = [self pathForTask];
_privateTasks = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
The following line of code is causing your problem:
return [documentDirectory stringByAppendingString:#"Tasks"];
The results in the returned path being something like:
.../DocumentsTasks
Note the lack of a slash.
Change the line to:
return [documentDirectory stringByAppendingPathComponent:#"Tasks"];
This will return a proper path and your code will work on a device.
It works in the simulator because you end up creating a file named DocumentTasks in some folder on your computer. But on a real device, the folder that this file is trying to be written to is read-only due to sandboxing.
Try getting the documents directory using the following code instead:
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
After getting the documents directory, you can get the path to a specific file by doing:
NSURL *fileURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"[FILE NAME]"];
I'm not sure why your code doesn't work, but this is the code I use on my app and it works in the simulator and the physical device.
Frequently code that works on the sim but not on the device is caused by filename upper/lower case mismatching.
The file system in Mac OS is almost always case-insenstive. (You can use disk volumes who's file system are case sensitive in Mac OS, but they are not by default.)
The simulator runs on Mac OS. It's file system is not case sensitive. So if you save a file as "Tasks" and then load it as "tasks" it works on the sim, but not on an actual iOS device. Make sure you check really carefully for mismatched case in your filenames.
My app was working perfectly in iOS 7, and now I'm facing some new bugs after switching to iOS 8 SDK.
For Ex. [NSFileManager defaultManager] file existence checking method ( fileExistsAtPath: ) is no longer working. Here's the details about current situation in my code:
This is the block of code whose condition never turns True :
File *tempFile = currentMessage.contains;
NSString *address = tempFile.thumbAddress;
if ([[NSFileManager defaultManager] fileExistsAtPath:currentMessage.contains.thumbAddress])
{
image = [UIImage imageWithContentsOfFile:currentMessage.contains.thumbAddress];
}
I have put a breakpoint before the if and traced it to see what is contains :
Printing description of address:
/Users/Unkn0wn/Library/Developer/CoreSimulator/Devices/C07E1D76-372E-4C9A-8749-50D369294FBA/data/Containers/Data/Application/1DC7DB3A-B0A2-43AE-9EDA-3E121786D1AA/Documents/FileAt141406917489510096thumbnail.jpg
I have checked the Finder to see if the file actually exists ( the address is copied from console so there's no chance of mistyping and typos in checking the path and file existence ) :
But that if block is not executed because fileExistsAtPath: returns NO.
Am I missing anything or it is just a bug of new SDK ? ( Because it was working perfectly with SDK 7.1.1 )
Any suggestions is highly appreciated.
Thanks
If thumbAddress is a full path (not a relative one), it can cause bugs when the app is updated because the app folder changes, for example, your first version of the app could be at that path:
/Users/Unkn0wn/Library/Developer/.../Application/ABCD/
When you update the app, the directory will change, for example:
/Users/Unkn0wn/Library/Developer/.../Application/EFGH/
So if you save a full path for your image in the first version of the app like :
ABCD/yourImage.jpg
And try to retrieve this image with the new version of the app, this image will not be found anymore as your image will now be at the path:
EFGH/yourImage.jpg
Hopes it helps!
EDIT
Maybe your absolute path is incorrect. Try calling it with a relative path:
NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path = [path stringByAppendingString:#"FileAt141406917489510096thumbnail.jpg"];
NSData *imageData = [NSData dataWithContentsOfFile:path]; // Should be != nil
I have an app that has several in app purchases in it and it also includes one free mp3 when the get the app in the first place and we have the list of mp3 they can play from when purchased and if they want to stream it and we also have a saved session section where they can move it offline and still be able to listen to it only here they can loop and do other things that would incur huge data costs.
The process goes like this I load the mp3 into the bundle and then upon opening the saved sessions view it checks to see if this file exists there if it doesn't then it copies it from the bundle location to the sandbox loacation and then proceeds normally so if it wiped out it will automatically recover itself from the bundle location.
The problem is this it wont't reload at all until at least one other file has been saved no matter what I do actvity wise in the app it just won't move that track in from the bundle UNTIL another track gets moved in first and I restart the app then the next time I go in I notice the slight delay of about a second and it is there in all its glory so I know I am close but I can't figure out why it won't initially do it.
Maybe someone out here can see what I ma missing it was late when I wrote the code so I will go for that as an excuse anyway here is the snippet of code I am working with
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dataPath = [docDir stringByAppendingPathComponent:#"Sessions"];
NSFileManager *filemgr = [NSFileManager defaultManager];
NSString *freeMp3FilePath = [dataPath stringByAppendingPathComponent:FREEMP3];
// Check if the file already exists
DLog(#"%#",freeMp3FilePath);
if (![filemgr fileExistsAtPath: freeMp3FilePath]){
DLog(#"File Not Found");
NSString *freeMP3Address = [[NSBundle mainBundle] pathForResource:#"m-app_0129instantconfidencehd" ofType:#"mp3"];
if([filemgr copyItemAtPath:freeMP3Address toPath:freeMp3FilePath error:nil]) {
DLog(#"File Copied");
} else {
DLog(#"File Not Copied %# %#",freeMp3FilePath,freeMP3Address);
}
}
In the log I see the "File Not Found" message and then I see the "File Not Copied" and the two paths do show up and look just as expected as seen here
2013-06-06 10:37:00.092 IMOB[51674:907] <SavedViewController.m:(57)> File Not Found
2013-06-06 10:37:00.097 IMOB[51674:907] <SavedViewController.m:(62)> File Not Copied /var/mobile/Applications/6D5463FF-4106-479A-8E77-16BD24B22CCF/Documents/Sessions/m-app_0129xxxhd.mp3 /var/mobile/Applications/6D5463FF-4106-479A-8E77-16BD24B22CCF/IMOB.app/m-app_0129xxxhd.mp3
This entry show nothings is in the directory and this also is the case if I shut down the app and restart it
2013-06-06 10:37:00.113 IMOB[51674:907] <SavedViewController.m:(169)> CURRENT ICON ARRAY COUNT :0
Ok hopefully this is something easy
Jeff
You should have added the error parameter when copying the file and checked what it contained...
Before you copy the file, ensure the destination directory exists using createDirectoryAtPath:withIntermediateDirectories:attributes:error:.
I want to distribute a populated database with my app. I am trying to implement the SQLitePlugin, but as the page says there is not any documentation for how to do it on iOS. I tried to implement this outdated steps but without any luck. Is there anyone who did this?
I found a solution at least it works for me so here is :
I used and followed the tutorial in the link you mentioned : http://gauravstomar.blogspot.fr/2011/08/prepopulate-sqlite-in-phonegap.html
Be sure to copy and past the good database.db and 000...001.db (the good one are either in /Caches and /Caches/file_0 folders or in /WebKit and /WebKit/file__0, i don't remember so try one then the other if it doesn't work). then i pasted them in my resources' project directory.
I modify the two lines :
NSString *masterPath = [libraryDir stringByAppendingPathComponent:#"WebKit/Databases/"];
NSString *databasePath = [libraryDir stringByAppendingPathComponent:#"WebKit/Databases/file__0/"];
by the following lines :
NSString *masterPath = [libraryDir stringByAppendingPathComponent:#"Caches/"];
NSString *databasePath = [libraryDir stringByAppendingPathComponent:#"Caches/file__0/"];
Remove your application from your simulator/device. And then run.. it works, my database is pre-populated.
I put the database in the Resources folder and placed this code in MainViewController.m.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *databasePath = [documentsDirectory stringByAppendingPathComponent:#"this.db"];
if ([fileManager fileExistsAtPath:databasePath] == NO) {
NSString *resourcePath = [[NSBundle mainBundle] pathForResource:#"this" ofType:#"db"];
[fileManager copyItemAtPath:resourcePath toPath:databasePath error:&error];
}
The following comes from a blog post - but as I've been slightly spanked for posting links before I'm going to quote from it. I'll post the URL at the end though and I recommend you go there for a full explanation and some follow up comments. This help comes credit Scott Buckel.
1) Use this plugin: https://github.com/chbrody/Cordova-SQLitePlugin/
2) Copy your sqlite db file to /assets folder of PhoneGap.
3) Then, follow instructions here: http://gauravstomar.blogspot.com/2011/08/prepopulate-sqlite-in-phonegap.html to copy the file to native storage. Change this.copy("Databases.db","/data/data/"+pName+"/app_database/");
3a) Instead of Databases.db, use your database filename.
3b) Instead of app_database, use "databases"
3c) You'll probably want to delete the file from /assets, since it is duplicated and no longer needed. My app was double the size it needed to be.
4) (Not sure if this step is necessary, I'm getting out of the office for the day). Edit SQLitePlugin.java
4a) Lines 176, I edited 1==1 so that if statement is always executed. Line 179 I changed this.setStorage(appPackage, false); to this.setStorage(appPackage, true);
5) You can then use the following command to open the DB and use it as any other PhoneGap database
5a) var db = window.sqlitePlugin.openDatabase("[full_database_name_including_extension]", "1.0", "PhoneGap Demo", 200000);
Full blog post: http://www.raymondcamden.com/index.cfm/2012/7/27/Guest-Blog-Post-Shipping-a-populated-SQLite-DB-with-PhoneGap
Again, I need someone's help. I am following the below tutorial for SQLite connection with FMDB wrapper:
http://www.icodeblog.com/2011/11/04/simple-sqlite-database-interaction-using-fmdb/
In the above tutorial, everything (creating a database and table, inserting, deleting) is done programmatically but everything works fine in simulator but when I use SQLite Manager add-on to make any insertion on the database (that was programmatically created in iOS), it doesn't show up in my testing device. Is there something that I am missing (like copying the file to my bundle) on my side? This is really driving me crazy. I am completely new to these.. Can anyone help me with this?
PS: I know I can use Core Data but for certain reasons I have to live with SQLite for this app. Any help would be greatly appreciated.
Thank you in advance.
Make sure to (a) include the db in the bundle (see here for screen snapshot of where the "copy bundle resources" can be found); and (b) programmatically copy db from bundle to documents. You can then open it from there.
Why it works on your simulator and not the device is a little curious. I can only imagine that you're reading from some fixed path, rather than programmatically retrieving the app's Documents folder?
Update:
I'd suggest checking your various return codes and make sure everything is ok.
I've taken your code sample and have (a) checked result of creation of FMDatabase; (b) checked result of open; (c) checked the result of FMResultSet, including the display of the sqlite error message; and (d) closed the result set:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsPath = [paths objectAtIndex:0];
NSString *path = [docsPath stringByAppendingPathComponent:#"DADatabase.sqlite"];
FMDatabase *database = [FMDatabase databaseWithPath:path];
NSAssert(database, #"Unable to create FMDatabase object");
NSLog(#"%#", database);
BOOL success = [database open];
NSAssert(success, #"Unable to open database");
FMResultSet *results = [database executeQuery:#"SELECT * FROM DrugList"];
NSAssert(results, #"Unable to create result set: %#", [database lastErrorMessage]);
while([results next]) {
NSString *name = [results stringForColumn:#"Drugname"];
[arrayToLoadDiseases addObject:name];
}
[results close];
[database close];
If you're running this in your simulator, you can go ahead and inspect the simulator's bundle and Documents folders if things don't go right, just to make sure everything is where it should be. You simulator's folder is something like "~/Library/Application Support/iPhone Simulator/5.1/Applications/" (replace the 5.1 with whatever version of your simulator you are using). You might have to unhide your Library folder, if you haven't already, by running the chflags nohidden ~/Library in a Terminal command-line window. Anyway, you can open up the simulator's database using Mac OS X's sqlite3 command and make sure your table is ok.
A common mistake is to fail to programmatically copy the database properly, thus the open method will create a blank database, and executeQuery will fail saying that the table was not found.
Let me know what you find.