1 / 0

Database-driven iPhone App

Database-driven iPhone App. CSE 390 Fall 2010. The purpose of this demo.

sailor
Download Presentation

Database-driven iPhone App

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Database-driven iPhone App

    CSE 390 Fall 2010
  2. The purpose of this demo In the previous demo we explored the Navigation application template for iOS, how to populate a table view from an array, how to build a multiple screen application, and how to load resources such as images and videos based on a user’s selection of an item in the table view. At the conclusion of the demo I said that there were notable limitations of the hard-coded approach. What if the data changes and I need to update it? What if I want to add additional items to display in the table view? I would have to recode and recompile the app. Furthermore the loading of the resources internally in the app made it a lot fatter than it needed to be (especially the video). So in this demo we will start to explore how to load data from a database, which in this case will still be internal to the app, but which could easily migrate to the web where it would be easy to update. The database will fetch the image resources from the web.
  3. SQLite 3 The are numerous options in iOS for storing data: plists (for small amounts of simple data, like a score in a game), Core data, and SQLite, among others. SQLite is a pretty well known and widely supported database, and that’s the one we will be using in this demo. Even here there are a few choices. On the Mac you can open up the terminal window and use the command line to create and populate your database. Or you can use a graphical database management tool like SQLite Manager (a free Firefox plug-in) or Navicat, a free stand-alone editor. To get SQLite Manager, just open up Firefox and select Add-ons from the Tools menu. Follow the links to the Add-ons web page and search for SQLite – then click to download it and add it to Firefox, where it will be added to your Tools menu. To download Navicat, follow this link: http://navicat.com/en/download/download.html. On the next slide I have included some screen shots from Navicat.
  4. Navicat Connecting to the (or creating a) database Double-click the table to edit it and add items Double-click the database to view its tables
  5. SQLite from the command line In the Terminal window (Applications > Utilities > Terminal) you can begin by typing at the prompt a few simple lines to create your database. The first line changes the directory to where you want the db to be created, and the next one creates the directory to hold it. The third line switches to that directory and the fourth line creates the database. cd /Users/teabones/Documents mkdir SQLiteMMlab cd SQLiteMMlab sqlite3 MMlab.sql Hit RETURN and you should now see the SQLite prompt, sqlite >
  6. Populating the database The first task is to create a table (CREATE TABLE), give the table a name, then give it the values you want. The main thing is to have a key to address the records in the table (the primary key, typically an integer). Then add the values you want for the data (the fields for each record). In this case they were a name (for the list in the table view), a description (for the text field in the detail view), and an imageURL (to load a screenshot into the detail view from a web server). The next task is to populate the database with some records, using the INSERT INTO command with your table name. The code is on the next slide.
  7. Creating the table and records CREATE TABLE projects ( id INTEGER PRIMARY KEY, name VARCHAR(50), description TEXT, imageURL VARCHAR(255) ); INSERT INTO projects (name, description, imageURL) VALUES ('SmartStep', 'SmartStep is a computer game that uses a dance pad to teach kids math.', 'http://www.mm.cs.sunysb.edu/MMpics/SmartStep.jpg'); INSERT INTO projects (name, description, imageURL) VALUES ('iSign', 'iSign is a speech recognition application that converts spoken English to video clips of American Sign Language.', 'http://www.mm.cs.sunysb.edu/MMpics/iSign.jpg'); INSERT INTO projects (name, description, imageURL) VALUES ('FingerSpell', 'FingerSpell is a gesture recognition application that converts American Sign Language gestures to synthesized speech.', 'http://www.mm.cs.sunysb.edu/MMpics/FingerSpell.jpg'); INSERT INTO projects (name, description, imageURL) VALUES ('WriteOn', 'WriteOn is a handwriting recognition application that helps students drill their spelling and penmanship skills.', 'http://www.mm.cs.sunysb.edu/MMpics/WriteOn.jpg');
  8. Finishing up After you have included all the records you need, hit RETURN to get to the sqlite > prompt. If you wish to check that everything was loaded, you can use the SELECT * FROM command with your table name to see a list of all the records in your table. When you are done. Simply type .quit at the prompt, hit RETURN, and close the terminal window. You should now see a folder with your database in it wherever you saved it on your Mac.
  9. Setting up the Xcode project Create a Navigation-Based application. This will by default give you a RootViewController which will be a table view. Add a detail view that the root view will link to by control-clicking the Classes folder and selecting Add > New File... In the iOS Cocoa Touch palette, choose the UIViewController subclass template, making sure to check that you want Xcode to generate the .xib (interface) file too. Name the file using Apple’s convention (ie. somethingViewController), and it will be added to your Classes directory. You can drag the .xib file to the Resources folder if you wish. You will also need to create a custom class to manage the database. Follow the same steps as in step 2 above, but this time you are going to choose the Objective-C class template, and make sure it is a subclass of NSObject. Name the file something like the table name in your database and a .h and .m file will be added to your Classes directory (no .xib file is generated).
  10. Importing the database and the SQLite Framework Control-click the Resources folder and select Add > Existing Files… and navigate to the location where you saved your SQLite database. Remember to check that you want the file to be copied to the destination directory in the pop-up window that appears. Control-click the Frameworks folder and select Add > Existing Frameworks… and search for libsqlite3.0.dylib. Confirm the addition of the framework in the pop-up that appears.
  11. Creating the database custom class In our example the Project.h file establishes that the Project object will have 3 properties: name, description, and imageURL. #import <UIKit/UIKit.h>@interface Project : NSObject { NSString *name; NSString *description; NSString *imageURL; } @property (nonatomic, retain) NSString *name; @property (nonatomic, retain) NSString *description; @property (nonatomic, retain) NSString *imageURL; -(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u; @end
  12. Custom database class (continued) The Project.m file stores the supplied data and returns the object (self). #import "Project.h” @implementation Project @synthesize name, description, imageURL; -(id)initWithName:(NSString *)n description:(NSString *)d url:(NSString *)u { self.name = n; self.description = d; self.imageURL = u; returnself; } @end
  13. The application delegate The application delegate will access the database, making it global for the whole app, so the SQLite framework needs to be imported. The MMlabAppDelegate.h looks like this: #import <UIKit/UIKit.h> #import <sqlite3.h>// Import the SQLite database framework @interface MMlabAppDelegate : NSObject { UIWindow *window; UINavigationController *navigationController; // Database variables NSString *databaseName; NSString *databasePath; // Array to store the project objects NSMutableArray *projects; } @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet UINavigationController *navigationController; @property (nonatomic, retain) NSMutableArray *projects; @end
  14. The application delegate (continued) The MMlabAppDelegate.m file is where we check to see if the database exists and to see if it has been copied from the application bundle to the user’s filesystem (documents folder). It then reads from the database (using the SQL statement SELECT * FROM) and populates the array, which will then be used to build the table view. The code for these methods (and some other housekeeping) follows on the next few slides.
  15. Importing and synthesizing #import "MMlabAppDelegate.h” #import "RootViewController.h” #import "Project.h"// Import the project object header @implementation MMlabAppDelegate @synthesize window; @synthesize navigationController; @synthesize projects; // Synthesize the projects array
  16. Set up and clean up (void)applicationDidFinishLaunching:(UIApplication *)application { // Setup some globals databaseName = @"MMlab.sql"; // Get the path to the documents directory and append the databaseName NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *documentsDir = [documentPaths objectAtIndex:0]; databasePath = [documentsDir stringByAppendingPathComponent:databaseName]; // Execute the "checkAndCreateDatabase" function [selfcheckAndCreateDatabase]; // Query the database for all project records and construct the "projects" array [selfreadProjectsFromDatabase]; // Configure and show the window [windowaddSubview:[navigationControllerview]]; [windowmakeKeyAndVisible]; } (void)dealloc { [projectsrelease]; [navigationControllerrelease]; [windowrelease]; [superdealloc]; }
  17. Check and create database -(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 = [NSFileManagerdefaultManager]; // Check if the database has already been created in the users filesystem success = [fileManager fileExistsAtPath:databasePath]; // If the database already exists then return without doing anything if(success) return; // 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 = [[[NSBundlemainBundle] resourcePath] stringByAppendingPathComponent:databaseName]; // Copy the database from the package to the users filesystem[fileManager copyItemAtPath:databasePathFromApp toPath:databasePatherror:nil];[fileManager release]; }
  18. Reading from the database -(void) readProjectsFromDatabase { // Setup the database object sqlite3 *database; // Init the projects Array projects = [[NSMutableArrayalloc] init]; // Open the database from the users filessytem if(sqlite3_open([databasePathUTF8String], &database) == SQLITE_OK) { // Setup the SQL Statement and compile it for faster access constchar *sqlStatement = "select * from projects"; sqlite3_stmt *compiledStatement; if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) { // Loop through the results and add them to the feeds array while(sqlite3_step(compiledStatement) == SQLITE_ROW) { // Read the data from the result row NSString *aName = [NSStringstringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)]; NSString *aDescription = [NSStringstringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)]; NSString *aImageUrl = [NSStringstringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)]; // Create a new project object with the data from the database Project *project = [[Projectalloc] initWithName:aName description:aDescription url:aImageUrl]; // Add the project object to the project Array [projectsaddObject:project];[project release]; } } // Release the compiled statement from memory sqlite3_finalize(compiledStatement); } sqlite3_close(database); } @end
  19. The RootViewController The table view can now be set up to display the data read into the array from the database, but first an instance of the projectViewController needs to be declared in the .h file. #import <UIKit/UIKit.h> #import "projectViewController.h” @interface RootViewController : UITableViewController { projectViewController *projectView; } @property(nonatomic, retain) projectViewController *projectView; @end
  20. The RootViewController.m file Setting up table views was covered extensively in the previous demo, so I won’t take much time with it here. The table display was kept simple as well. There are 3 main parts to the code: importing resources, setting up the cell, and switching to the detail view once the user has selected an item of interest from the table. The code follows on the next slides.
  21. Importing assets and setting up #import "RootViewController.h” #import "MMlabAppDelegate.h” #import "Project.h” @implementation RootViewController @synthesize projectView; (void)viewDidLoad { [superviewDidLoad]; self.title = @"Research"; }
  22. Configuring the table cells // Customize the number of rows in the table view. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { MMlabAppDelegate *appDelegate = (MMlabAppDelegate *)[[UIApplicationsharedApplication] delegate]; return appDelegate.projects.count; } // Customize the appearance of table view cells. (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { staticNSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCellalloc] initWithFrame:CGRectZeroreuseIdentifier:CellIdentifier] autorelease]; } // Configure the cell. MMlabAppDelegate *appDelegate = (MMlabAppDelegate *)[[UIApplicationsharedApplication] delegate]; Project *project = (Project *)[appDelegate.projectsobjectAtIndex:indexPath.row];[cell setText:project.name]; return cell; }
  23. Switching to the detail view (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // Navigation logic -- create and push a new view controller MMlabAppDelegate *appDelegate = (MMlabAppDelegate *)[[UIApplicationsharedApplication] delegate]; Project *project = (Project *)[appDelegate.projectsobjectAtIndex:indexPath.row]; if(self.projectView == nil) { projectViewController *viewController = [[projectViewControlleralloc] initWithNibName:@"projectViewController"bundle:nil]; self.projectView = viewController;[viewController release]; } // Setup the animation[self.navigationControllerpushViewController:self.projectViewanimated:YES]; // Set the title of the view to the project's name self.projectView.title = [project name]; // Set the description field to the project description[self.projectView.projectDesciptionsetText:[project description]]; // Load the project image into a NSData object and then assign it to the UIImageView NSData *imageData = [NSDatadataWithContentsOfURL:[NSURLURLWithString:[project imageURL]]]; UIImage *projectImage = [[UIImagealloc] initWithData:imageData cache:YES]; self.projectView.projectImage.image = projectImage; }
  24. The projectViewController The projectViewController is where some text about a Multilab research project will be shown and a screenshot will be fetched from the server. This is very basic stuff for us by now. The .h file simply needs to declare 2 outlets for Interface Builder, the projectDescription and projectImage, and the only thing the .m file does is synthesize their properties. A UITextView object was added to the View in Interface Builder, along with a UIImageView object, and they were connected to their outlets in the Inspector window.The .h declarations are below: #import <UIKit/UIKit.h> @interface projectViewController : UIViewController { IBOutletUITextView *projectDesciption; IBOutletUIImageView *projectImage; } @property (nonatomic, retain) IBOutlet UITextView *projectDesciption; @property (nonatomic, retain) IBOutlet UIImageView *projectImage; @end
  25. Success!
  26. What’s next? So that was a fair amount of work just to load some text and a few images. But if we had a much larger amount of content to display we would want to be able to manage the database from our app, such as adding, deleting, and editing items, and even searching for items. If we had a lot of users accessing the data, we would want to be able to manage the database centrally (online). That would require we also think about the security of the data and access to it. Other resources, like video, and even the text descriptions, would be better managed online. Finally the app would still be able to store data locally (at least the non-BLOB data) so that a persistent network connection wasn’t needed. Edits to the data made locally by the app would be uploaded to the online db – the Store and Forward architecture we discussed earlier in the semester.
More Related