Read only Sqlite ?

I have this application on my iPhone based on a sqlite database. It reads and displays data correctly.

Attempting to update or insert data give me this message: “attempt to write a readonly database.”

Any clue of the cause of this message ?

Where are you storing the database?
If it is in /RESOURCES that is the reason

That was it. Thank you.

I have the same problem, but I don’t understand the answer of Dave; where do I have to store the database file?

I usually store databases of iPhone apps in the documents folder.
If you want to distribute data with your app, you could store a “default” data file in the resources folder. On the first run you can open that database as db1 for instance. Then create a new databasefile in the documentsfolder as db2. Finally use something like db1.backup( db2, nil, -1) to copy the data and structure to the writable database file. When your app needs to connect to the database, use the db2 file.
Later, if a user wants to revert to the default data, backup the data to db2. Worked with me.

But then… copying the file to the documents folder might work as well. Funny that I haven’t tried that though :wink:

Er… I see that the backup method is not available for the iOS’ SQLite database…
Well… just copy the database file from the resources folder to the documents folder, in case you have some data you want to distribute with your app :slight_smile:

Thanks Edwin, but that is not a workaround I’d like to implement. I’d rather use the CopyFiles step in the build settings of the IDE. Specifying the resources folder makes the database perfectly read/write in the simulator, but not on an iOS device. Doesn’t make sense.

Makes perfect sense if you realize what Apples intent is… /Resources are considered to be “part of the application”, the same schema is used in OSX programs (an APP is not a single file, but in reality is a directory structure)
But if Apple were to allow you to write into the /Resources directory (or even worse delete files), then the integrity of the APP would be broken, so in order to maintain not only the integrity, but more important the security, /Resources is READ ONLY

Technically the simulator should enforce that as well, but it may obey the permissions of OSX in which case it doesn’t really “know” that an “app” is involved, since it is being “emulated”.

But as mentioned above… you can either use code to create the database if it is not already in /Documents, or you can include a pre-populated template database and copy it to /Documents as required.

Thanks Dave. I understand. I meant that it doesn’t make sense to me that the “CopyFiles” step is not something I can copy files with when I build for deployment on a device. I indeed do have a couple of pre-poluated db-files which are quite large, so I’ll do some coding to move instead of copy I guess. Thanks :wink:

An alternative to storing your database in Documents is to store it in Caches (SpecialFolder.Caches). Apple’s docs state that the Documents folder is the place to store user-generated content that can’t be recreated by the app and there are reports of apps being rejected for storing large amounts of their own data within Documents.

In my app I use an SQLite database to cache data retrieved from web services, so I store that database in the Caches folder alongside images (also retrieved via web services) as this data doesn’t need to be backed up and can easily be recreated.

Another advantage to “/Documents” that may or may not be applicable to Caches is the via iTunes you can copy data to and from the device (this does require setting a flag in the Plist file). I use this feature to move the database between the iOS version of my app and the desktop version. Kind of a poor mans Synch

It can’t. Copy Files Steps are done when you are building your app, not when it is run. Use Xojo.IO.SpecialFolder.GetResource to get a reference to your DB file that was copied to Resources and then copy it out to where you want (perhaps Documents).

Some steps are described in Copying Files to the Device.

Very true. Apple recommends Caches only for data that the app can recreate; not user-generated content. In my app when a user takes a photo I save it into Documents as it is user-generated. Then, once the photo has synced with my web services, I move it into Caches. I also set the iTunes File Sharing entry in the plist so that the user can access any un-synced Documents through iTunes should they have a sync problem and need to get them off the device.

So, for some “default” dataset the resource folder can be used, right?

So, when an app needs a file, a Photo in your case, you look for it in Caches first, if not found, look for it in Documents?
What is the best practice of using caches? Is it smart to remove files that were not needed accessed for a certain amount of time? (to save space on smaller devices)

[quote=226238:@Edwin van den Akker]So, when an app needs a file, a Photo in your case, you look for it in Caches first, if not found, look for it in Documents?
What is the best practice of using caches? Is it smart to remove files that were not needed accessed for a certain amount of time? (to save space on smaller devices)[/quote]

I have an SQLite database in Caches which represents most of my cached (offline) data. The database has an Images table and it records the status of every photo that the user has in the app so the app uses that to find the photo in either Caches or Documents or download it from a service if it has not yet been cached.

Apple states that the Caches folder can be emptied by the OS if it needs space so that’s why you only want to use it for content that your app can re-create. In my case because we are dealing with a large number of images that don’t need to always be at hand, Caches seems like the logical place to put them. If we put them in Documents I believe we would eventually receive complaints from users about their backup sizes (particularly iCloud backups) as the Documents folder is backed up.

Ok, so it is not necessary to have the app deal with data in the caches folder? I mean, remove data that has not been accessed for a while? (since the OS will deal with it)

Yes you can just leave files in Caches, the user never sees them and the OS will delete them if it needs the space. I’ve never seen this happen on any of our internal devices, though, but that seems to be the way it works. :slight_smile:

Thanks Jason!

It might be handy to make a class to deal with files like this. I mean, some kind of class I can re-use all the time. Like the way folderitem works.
iOSfile.child(“myPhoto.png”) will return a folderitem to myPhoto.png.
And this iOSfile will look for a copy in Caches, or documents… and finally looks online, to download it to caches. And will pass the right reference… right?

(or documents first, then caches… just in case the user edited the data, or check the modified timestamp first… or whatever sync algorithm)

[quote=226246:@Edwin van den Akker]Thanks Jason!

It might be handy to make a class to deal with files like this. I mean, some kind of class I can re-use all the time. Like the way folderitem works.
iOSfile.child(“myPhoto.png”) will return a folderitem to myPhoto.png.
And this iOSfile will look for a copy in Caches, or documents… and finally looks online, to download it to caches. And will pass the right reference… right?[/quote]

I have a Document class (because images are just one type of document that my app deals with) which does those things. Remember that the HTTPSocket is asynchronous so if you have a method to return an image and the image is “online” (i.e. not on the device) then you’ll need to call back to another method (e.g. a delegate) once you have the image. In my app I display a download icon in place of the image if the image isn’t on the device and then, when I have the image in Caches, I pass the image to the delegate method so it can be updated in the view.