I am a Swift newbie currently working on an IOS application, which needs to access an existing static database (size 400kb) of 1 table with about 3300 rows, and 26 columns. This database was initially a CSV file, converted into an SQLite file.
From forums I read online, it is to my understanding that SQLite queries are incredibly fast, and for that reason should be the preferred choice. I will only need to be reading the database and will not perform any writes.
I have found a number of old tutorials online which have utilized Objective-C or tutorials from several years ago which utilize swift 2 or 3. A newer solution I found was to use this SQLite wrapper: https://github.com/stephencelis/SQLite.swift. However, I am not entirely sure how to implement it. I was wondering if it was possible to read directly from my bundled database, or if I had to create a new table and copy from the bundled database.
It looks like SQLite.swift will get the job done for you. From the documentation on the page you linked it looks like you use Connection(pathToDB) to start using the library.
Since you're bundling the database and don't plan on modifying it you should be able to use Bundle.main.path(forResource:, ofType:) to get the path to your bundled database. If you want to modify it, you'll probably want to copy it to the documents directory and then reference that copy.
Another good answer on getting paths to various kinds of bundle resources if you need more help:
How to get path of image form Resource of main bundle
Related
I have some general questions about iphone app updates that involves sqlite db.
With the new update does the existing sqlite db get overwritten with a copy of the new one?
If the update doesn't involve any schema changes then the user should be able to reuse the existing database with their saved data, right? (if the existing database doesn't get overwritten from 1 above )
If there are some schema changes, what's the best way to transfer data from the old database into the new one? Can some one please give me guidelines and sample code?
Only files inside the app bundle are replaced. If the database file is in your app's Documents directory, it will not be replaced. (Note that if you change files inside your app bundle, the code signature will no longer be valid, and the app will not launch. So unless you are using a read-only database, it would have to be in the Documents directory.)
Yes.
What's best depends on the data. You're not going to find sample code for such a generic question. First, you need to detect that your app is running with an old DB version. Then you need to upgrade it.
To check versions:
You could use a different file name for the new schema. If Version2.db does not exist but Version1.db does, do an upgrade.
You could embed a schema version in your database. I have a table called metadata with a name and value column. I use that to store some general values, including a dataversion number. I check that number when I open the database, and if it is less than the current version, I do an upgrade.
Instead of creating a table, you could also use sqlite's built-in user_version pragma to check and store a version number.
You could check the table structure directly: look for the existence of a column or table.
To upgrade:
You could upgrade in place by using a series of SQL commands. You could even store a SQL file inside your app bundle as a resource and simply pass it along to sqlite3_exec to do all the work. (Do this inside a transaction, in case there is a problem!)
You could upgrade by copying data from one database file to a new one.
If your upgrade may run a long time (more than one second), you should display an upgrading screen, to explain to the user what is going on.
1) The database file isn't stored as part of the app bundle so no, it won't get automatically overwritten.
2) Yes - all their data will be saved. In fact, the database won't get touched at all by the update.
3) This is the tricky one - read this fantastically interesting document - especially the part on lightweight migration - if your schema changes are small and follow a certain set of rules, they will happen automatically and the user won't notice. however, if ther are major changes to the schema you will have to write your own migration code (that's in that links as well)
I've always managed to get away with running lightweight migrations myself - it's by far easier than doing it yourself.
What I do is that I create a working copy of the database in the Documents directory. The main copy comes with the bundle. When I update the app I then have the option to make a new copy over the working copy, or leave it.
I would like to know if it is possible to create the file of a database by programming?
Actually I need to create a database if it does not exist.
I'll assume you have your own valid reasons for using sqlite3 directly rather than Core Data. There are certainly cases where it's appropriate.
The sqlite_3_open() function will create the database if it doesn't already exist. The sqlite3_open_v2() function will create the database if you pass SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE in the flags parameter. See the documentation for more details.
Of course on iPhone you'll need to make sure you're creating the database in a read-write directory such as the app's Documents directory, as opposed to the Resources directory, which is read-only.
In practice I've never tried building a database from the ground up on the iPhone. I always found it simpler to just include an empty DB file with the schema pre-built as an application resource, and then copy the file to the Documents directory the first time the app is run.
Are you sure that you need to create the database file directly? Maybe you should check out the Core Data Framework.
Thanks for your answers, I have never used Core Data so I will have a look on this.
For the moment I also copy a DB file from the Resource directory to the Documents but I would like to create a static library which can be used by many persons. So I would give a minimum of files to add to their project. That's the reason.
I currently have an iPhone app that reads data from an external XML file at start-up, and then writes this data to the database (it only reads/writes data that the user's app has not seen before, though)
My concern is that there is going to be a back catalogue of data of several years, and that the first time the user runs the app it will have to read this in and be atrociously slow.
Our proposed solution is to include this data "pre-built" into the applications database, so that it doesn't have to load in the archival data on first-load - that is already in the app when they purchase it.
My question is whether there is a way to automatically populate this data with data from, say, an XML file or something. The database is in SQLite. I would populate it by hand, but obviously this will take a very long time, so I was just wondering if anybody had a more...programmatic solution...
I'm going to flesh out Jason's answer, I've marked my post as a community wiki so I shouldn't get any points for this.
He's not talking about a dummy app - write the app as you normally would, but check to see if the database exists in your main bundle before you call the code that populates the plist. You run that in the simulator, pull out the generated sqllite database, and add it to your project - if you only need to read from it, you can read it from the main bundle directory. If you need to do further writes then copy it into the writable documents area, and use it from there. So basically for the main user, the code to populate the DB would never be called...
The only downside is you also end up including the plist files you are reading from, even though you only need the database. You could make a different build target that was a copy of the main one with the only difference being that it held the plist files, while the main target you built for the app store did not.
Not to take Jason's answering thunder, I can't comment yet so it has to be here.
The nice thing is that you can access the filesystem of the simulator right on your Mac. I am away from mine at the moment or I could tell you exactly where to look, but I just find it by putting the name of the db file into searchlight and just running with that.
You also do not need to wright any code to populate the db since you can use the command line tool to do the initial setup if that is more convenient.
You will need to copy it over though since resources are stored in the read only signed portion of the app bundle.
I had the same problem of you using sqlite, on massive insert it's really slow. So the best way it's provide directly a filled sqlite database.
You have another way, instead of INSERT INTO, to populate a sqlite db. You can produce a csv file for each table and load into the tables using your computer and the sqlite shell:
Just 2 simple commands:
.separator SEPARATOR
.import FILE TABLE
Example:
adslol:~ user$ sqlite3
SQLite version 3.6.12
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .separator ;
sqlite> .import myData.csv nameOfMyTable
sqlite> .quit
I hope it's what you was looking for :)
If you need a good client for sqlite3 try SQLite Manager, it's a Firefox add-ons.
i am working on an application that displays read-only data i am shipping.
it is more of a book.
It is easy with SQLite but i am not satisfied with the performance and trying to use Core Data.
The issue is with pre-filling Core Data is that it is a hard process.
My question is:
Is it possible to build an assistant iphone application (for me to use) which uses the same data model for pre-filling.
and then take the populated .xcdatamodel file and use it in my original application?
I hope this makes sense :)
Adham
I believe what you're asking is whether you can create a CoreData database upfront and copy it to the iPhone. Is that correct?
This article will help. Here's a quote:
I thus suggest the following five-step process:
Create your data in a comma-separated file, typically placing each row of data (an entity) in a row of the file and separating different columns (its attributes) by commas.
Write a standalone program and copy in your .xcdatamodel file from your main project.
Write code in your new program that parses your comma-separated file and inserts the information into a Core Data persistent store that should be identical to the persistent store in your main project.
Run the program in the Simulator
Copy your data from the Simulator's documents directory into your actual project's bundle.
It's possible, I've done it. I made a desktop application to read from a CSV file using the code here:
http://www.mac-developer-network.com/columns/coredata/may2009/
I just had to alter the way the CSV part worked, and change the model.
I copied and pasted my model from the model builder into the iPhone model. (Clicked on the "grid" area, selected all, copied)
Then I took the sqlite database the desktop app produced (found it in Application Support, in the folder for this application) and put it into the resources folder
I made some code to copy the sqlite into the documents folder on the iPhone (if it wasn't already there) at startup, in the applicationDidLaunch method. It's possible that having it in the resources folder is no good. Even though you're using the database as read only, Core Data may want to write something to it. Not sure about this though..
I used the sqlite file in the documents folder in my Core Data set up.
The desktop and iPhone Core Data sqlite file seem to be exactly the same format. You can transfer one sqlite file to another application (iPhone to iPhone too) as long as they have the same data model. In another application, I used NSXMLParser to create the Core Data sqlite file, then transferred it to another app, both on iPhone using the Simulator.
Yeah, your data source can be whatever you want it to be. The other suggestions are good ones. Create a managed object model (.xcdatamodel) identical to what you want to use in your app. Read in the data from your file, create a new instance of your managed object and populate it from the file. Then save, and dive into the bundle in the iPhone Simulator and copy it over. This has the added bonus of being in exactly the format you need, with all the helpful metadata. Copy your object model and your managed object classes and you're good to go.
Note, though, if you really intend for it to be read-only, and you're using it at install, it will be installed in your finished app's bundle (under Applications/{SIGNATURE}/Myapp.app). If you intend to edit this database or allow a user to save to it, it's a better idea to copy it to the Applications/{SIGNATURE}/Documents directory where your user database lives.
I am trying to learn SQLite, and I am building an iPhone app. But I would like to add an SQLite database to my building app. I have got three tutorials, but I am not clear on that code.
How can I add an SQLite database to my building app? What would sample code look like?
First of all you need to create your database.
From the command line create your db file.
sqlite3 mydb.db
Then create the tables within your database
CREATE TABLE tags (id int(5), name varchar(255), created_at datetime, updated_at datetime);
Repeat that for any tables that you want in your database.
Then you need to include the database file in your project. Add the existing database file to your project as you would any other existing file.
Next you will have to link in the framework to interact with the database. This can be found under you current iPhone SDK folder.
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/usr/lib/libsqlite3.0.dylib
Finally you have to include the header file sqlite3.h from
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/usr/include/sqlite3.h
It should now be possible to write code to access your sqlite database from within your iPhone application.
There is lots of information on the web.
Have you looked at the demo application? SQLite Book List This shows examples of common database functions under SQLite. This is effectively using the standard SQLite C APIs.
There are Objective C wrappers which may suite you more.
EntropyDB, SQLitePersistenceObjects and FMDB.
I found this Tutorial and this list of resources which may help.
Recently I've been using an ORM SQLite.net It is the way to go for me but then I'm developing in MonoTouch C#.
Tony
I'd also recommend looking at FMDB. It makes using SQLite slightly more Objective-C/Cocoa-like. It's not a full ORM wrapper or anything though; it just wraps the C API into something a bit more flavoursome.
http://sqlite.org/docs.html is a good place to start.
You might get more useful help if you are more specific about what you are trying to do, and what obstacles you are encountering.
If you use Firefox, there's this handy addon that you can use to manage and create an SQLite database.
you will have to link in the framework to interact with the database. This can be found under you current iPhone SDK folder.
/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/usr/lib/libsqlite3.0.dylib
CoreData should help, but I can't find it anywhere in the list of importable Frameworks.
You could take a peek at the iPhone examples, especially the SQLite Book List example.