I'm working on an iPhone project in Xcode 4.3 with SQlite3, the connection between the SQlite and Xcode is done, now I want to display my data into a table views (three views) and its read only!
so I have the main table view, select raw --> take to 2nd view and load other data from the DB select raw --> take to the details view to display long text and image!
Any help appreciated.
AppDelegate.h
#import "AppDelegate.h"
#import "MasterViewController.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize navigationController = _navigationController;
- (void)dealloc
{
[_window release];
[_navigationController release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *dbPath = [documentsDir stringByAppendingPathComponent:#"cities.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL success = [fileManager fileExistsAtPath:dbPath];
if (success) {
NSLog(#"we have the database");
} else {
NSLog(#"we have no database");
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"cities.sqlite"];
BOOL moved = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:nil];
if (moved) {
NSLog(#"database copied");
}
}
MasterViewController *masterViewController = [[[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil] autorelease];
self.navigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
MasterViewController.h
#import <UIKit/UIKit.h>
#import <sqlite3.h>
#class DetailViewController;
#interface MasterViewController : UITableViewController {
NSMutableArray *cities;
}
#property (strong, nonatomic) DetailViewController *detailViewController;
#end
MasterViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
students = [[NSMutableArray alloc] init];
countries = [[NSMutableArray alloc] init];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)] autorelease];
self.navigationItem.rightBarButtonItem = addButton;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSString *dbPath = [documentsDir stringByAppendingPathComponent:#"cities.sqlite"];
sqlite3 *database;
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
const char *sqlStatement = "select * from cities_info";
sqlite3_stmt *compileStatement;
if (sqlite3_prepare_v2(database, sqlStatement, -1, &compileStatement, NULL) == SQLITE_OK) {
while (sqlite3_step(compileStatement) == SQLITE_ROW) {
NSLog(#"one record");
NSString *cityName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compileStatement, 1)];
[cities addObject:cityName];
}
NSLog(#"cities: %#",cities);
}
} else {
NSLog(#"error in database");
}
}
Blockquote
I suggest a light wrapper over SQLite - see https://github.com/JohnGoodstadt/EasySQLite
This will allow:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _personTable.rows.count;
}
AND
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
NSArray* row= _personTable.rows[indexPath.row];
cell.textLabel.text = row[[_personTable colIndex:#"lastname"]];
...
Set this up by using an iVar representing a SQL Table:
self.personTable = [_db ExecuteQuery:#"SELECT firstname , lastname , age , salary FROM person"];
And a DB Connection iVar passing in your SQL file name:
self.db = [DBController sharedDatabaseController:#"DataTable.sqlite"];
First of all, I suggest using FMDB, which is an Objective-C wrapper around sqlite3. Secondly, I'd create a custom Data Access Object with a shared instance, like so:
#interface MyDatabaseDAO : NSObject
#property (nonatomic, strong) FMDatabase *database;
#end
#implementation MyDatabaseDAO
#synthesize database = _database;
+ (MyDatabaseDAO *)instance {
static MyDatabaseDAO *_instance = nil;
#synchronized (self) {
if (_instance == nil) {
_instance = [[self alloc] init];
}
}
return _instance;
}
- (id)init {
self.database = [FMDatabase databaseWithPath:myDatabasePath];
[self.database open];
}
- (void)dealloc {
[self.database close];
}
#end
This DAO must have 3 access methods: one for each data object in the database. Because you weren't specific, I made these objects without any specific properties.
- (NSArray *)retrieveAllFirstViewItems {
NSMutableArray *items = [NSMutableArray array];
FMResultSet *resultSet = [FMDBDatabase.database executeQuery:#"SELECT * FROM myFirstViewItemTable"];
while ([resultSet next]) {
// extract whatever data you want from the resultset
NSString *name = [resultSet stringForColumn:#"name"]
[items addObject:name];
}
[resultSet close];
return items;
}
- (MySecondViewItem *)retrieveSecondViewItemFromIndexPath:(NSIndexPath *)indexPath {
FMResultSet *resultSet = [FMDBDatabase.database executeQuery:#"SELECT * FROM mySecondViewItemTable WHERE pid = ?", [indexPath indexAtPosition:0]];
if ([resultSet next]) {
// extract whatever data you want from the resultset
NSString *name = [resultSet stringForColumn:#"name"]
MySecondViewItem *mySecondViewItem = [[MySecondViewItem alloc]
initWithName:name withPID:[indexPath indexAtPosition:0]];
[resultSet close];
return mySecondViewItem;
} else {
return nil;
}
}
- (MyThirdViewItem *)retrieveThirdViewItemFromIndexPath:(NSIndexPath *)indexPath {
FMResultSet *resultSet = [FMDBDatabase.database executeQuery:#"SELECT * FROM mySecondViewItemTable WHERE pid = ?", [indexPath indexAtPosition:1]];
if ([resultSet next]) {
// extract whatever data you want from the resultset
NSString *name = [resultSet stringForColumn:#"name"]
MyThirdViewItem *myThirdViewItem = [[MyThirdViewItem alloc]
initWithName:name withPID:[indexPath indexAtPosition:1]];
[resultSet close];
return myThirdViewItem;
} else {
return nil;
}
}
Since it's read-only, these are all the required methods. In your first UITableView, just implement method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MySecondViewItem *mySecondViewItem = [[MyDatabaseDAO instance] retrieveSecondViewItemFromIndexPath:indexPath];
//instantiate a view from this item and use [UINavigationController pushViewController:animated:] to navigate to it
}
All that's left is just to show your data objects in views somehow. I sugget doing as much of the data retrieval as possible in the Data Access Object so that the view controllers can read the properties of the data objects without having to worry about the backend.
That's all there is to it! I hope this helped
Related
I've got a search page at the moment which will load a list of results for a web-service, but when I return to the search page I would like to 'save' whatever was entered (e.g. 'resto italian') and then display that entry and previous entries into a table view below, like in my following image:
My plan was to use property list serialization - if there isn't already a list, create a property list called history.plist, and populate it with each search term that is made, and display the nearest ten in the table view like above.
What I've tried:
// should create history.plist
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingString:#"history.plist"];
}
/* This is the action for when 'search' is clicked - calls the method above to create
a new plist if it's not already created.
I then try to display the contents of the of the file in the textfield itself
(for testing purposes) but it's not saving/displaying properly at the moment. */
- (IBAction)saveHistory:(id)sender {
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
for (int i = 0; i < (sizeof(array)); i++) {
UITextField *theField = self.searchHistory;
theField.text = [NSString stringWithFormat:#"%#", array];
}
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];
}
Any links to tutorials attempting to do this, suggestions towards what I should do, or improvements to what I have would be greatly appreciated.
This should fix the problem:
// This is inside viewDidLoad
UIApplication *myApp = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:myApp];
// This is inside my table view - where I'm loading the file data to display in table cells
NSString *myPath = [self dataFilePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:myPath];
if (fileExists) {
NSArray *values = [[NSArray alloc] initWithContentsOfFile:myPath];
for (int i = 0; i < values.count; i++) {
cell.historyDisplay.text = [NSString stringWithFormat:#"%#", [values objectAtIndex:i]];
}
}
// This is the file path for history.plist
- (NSString *)dataFilePath {
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
return [[path objectAtIndex:0] stringByAppendingString:#"history.plist"];
}
// This is my search button - I want to save whatever was typed in the text field, into history.plist, to display in my tableview whenever a user goes to it.
- (IBAction)saveHistory:(id)sender {
NSMutableArray *values = [[NSMutableArray alloc]initWithContentsOfFile:[self dataFilePath]];
if(searchInputTextField.text.length > 0)
[values addObject:searchInputTextField.text];
[values writeToFile:[self dataFilePath] atomically:YES];
[leTableView reloadData];
}
I would use my suggest in comments, but here's some edits to your code that might help in the meantime.
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
for (int i = 0; i <array.count; i++) {
//I don't know what this line means
UITextField *theField = self.searchHistory;
//Change this line to this
theField.text = [NSString stringWithFormat:#"%#", [array objectAtIndex:i]];
}
I would use Core Data, creating a class, i.e. HistoryRecord with attributes termSearched and timestamp of type NSString and NSDate respectively.
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface HistoryRecordManagedObject : NSManagedObject
#property (nonatomic, retain) NSString *termSearched;
#property (nonatomic, retain) NSDate *timestamp;
+ (NSArray *)findEntity:(NSString *)entity withPredicate:(NSPredicate *)predicate
#end
Implementation
#import "HistoryRecordManagedObject.h"
#implementation HistoryRecordManagedObject
#dynamic termSearched;
#dynamic timstamp;
+ (NSArray *)findEntity:(NSString *)entity withPredicate:(NSPredicate *)predicate
{
NSError *error;
NSArray *fetchedObjects;
/* After set all properties, executes fetch request */
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:entity
inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entityDesc];
[fetchRequest setPredicate:predicate];
fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
return fetchedObjects;
}
#end
Of course that's not just this! There are some extra stuff that must be done to use Core Data such as create the model. Read a little about it! It's worth!
Good luck!
In the action for searching, just save the search result to NSUserDefaults.
NSMutableArray *searches = [[NSUserDefaults standardUserDefaults] arrayForKey:#"searches"];
[searches insertObject:textField.text atIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:searches forKey:#"searches"];
[[NSUserDefaults standardUserDefaults] synchronize];
Then load the same array for the tables data source and reload the table in viewwillappear and when keyboard is dismissed.
Replace your saveHistory function by below way:
- (IBAction)saveHistory:(id)sender
{
NSMutableArray *values = [[NSMutableArray alloc]initWithContentsOfFile:[self dataFilePath]];
if(searchInputTextField.text.length > 0)
[values addObject:searchInputTextField.text];
[values writeToFile:[self dataFilePath] atomically:YES];
[leTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return values.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [values objectAtIndex:indexPath.row];
}
Am am making a task organizer iOS app. You type a task and it is saved in an array. I wanted people to be able to share the tasks between Phones so i added a way to save each Array.
Right now I am using my idea locally. The page has a title and a password. When the save button is pressed the array is saved to a file (This works very well and it saves every time) that is unique to the Title and Password.
I need to find a way to then get all the information in the file back to the array so it can be seen. This is what i have tried and keep in mind that everything works fine except for the "get tasks button" my problem is in the getFile void:
BNRAppDelegate.m
#import "BNRAppDelegate.h"
NSString *docPath()
{
NSArray *pathList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
return [[pathList objectAtIndex:0] stringByAppendingPathComponent:#"data.td" ];
}
#implementation BNRAppDelegate
#synthesize window = _window;
#pragma mark - Application delegate callbacks
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSArray *plist = [NSArray arrayWithContentsOfFile:docPath()];
if (plist)
{
tasks = [plist mutableCopy];
}
else
{
tasks = [[NSMutableArray alloc] init];
}
CGRect windowFrame = [[UIScreen mainScreen] bounds];
UIWindow *theWindow = [[UIWindow alloc] initWithFrame:windowFrame];
[self setWindow:theWindow];
[[self window] addSubview:taskTable];
[[self window] addSubview:taskField];
[[self window] addSubview:titleField];
[[self window] addSubview:insertButton];
[[self window] addSubview:clearButton];
[[self window] addSubview:shareButton];
[[self window] addSubview:passField];
[[self window] addSubview:getButton];
[[self window] setBackgroundColor:[UIColor whiteColor]];
[[self window] makeKeyAndVisible];
return YES;
}
- (void)addTask:(id)sender
{
NSString *t = [taskField text];
if ([t isEqualToString:#""]) {
return;
}
[tasks addObject:t];
[taskTable reloadData];
[taskField setText:#""];
[taskField resignFirstResponder];
}
- (void)takeTask:(id)sender
{
[tasks removeAllObjects];
[taskTable reloadData];
[tasks writeToFile:docPath()
atomically:YES];
}
- (void)saveTask:(id)sender;
{
if ([titleField text] == #""){
//
} else {
NSString * original = [titleField text];
NSString * pass = [passField text];
NSString * step = [NSString stringWithFormat:#"%#.%#", original, pass];
NSString * file = [NSString stringWithFormat:#"%#.plist", step];
[tasks writeToFile:[NSString stringWithFormat:#"/tmp/%#", file]
atomically:YES];
[tasks writeToFile:docPath()
atomically:YES];
}
}
- (void)getFile:(id)sender;
{
NSString * original = [titleField text];
NSString * pass = [passField text];
NSString * step = [NSString stringWithFormat:#"%#.%#", original, pass];
NSString * file = [NSString stringWithFormat:#"%#.plist", step];
NSMutableArray *theTasks = [NSMutableArray arrayWithContentsOfFile:[NSString stringWithFormat:#"/tmp/%#", file]];
tasks = [theTasks mutableCopy];
[tasks writeToFile:docPath()
atomically:YES];
}
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tasks removeObjectAtIndex:indexPath.row]; [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
#pragma mark - Table View management
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [tasks count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *c= [taskTable dequeueReusableCellWithIdentifier:#"Cell"];
if (!c) {
c = [[ UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
NSString *item = [tasks objectAtIndex:[indexPath row]];
[[c textLabel] setText:item];
return c;
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[tasks writeToFile:docPath()
atomically:YES];
}
- (void)applicationWillTerminate:(UIApplication *)application
{
[tasks writeToFile:docPath()
atomically:YES];
}
#end
Please Help if you can Thank You.
I think you are doing it on the wrong way. I dont know what is the used of the data.td on your code since you want to save it as username.password.plist
Please try this one, and it might guide you how save and retrieve files locally base on your code.
NSString *pathPlist(NSString *filename)
{
NSArray *pathList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
return [[pathList objectAtIndex:0] stringByAppendingPathComponent:filename];
}
- (void)saveTask:(id)sender {
NSString * original = #"Hello";
NSString * pass = #"123";
NSString * step = [NSString stringWithFormat:#"%#.%#", original, pass];
NSString * file = [NSString stringWithFormat:#"%#.plist", step];
NSString *path = pathPlist(file);
NSMutableArray *array = [[NSMutableArray alloc] init];
if (path) {
NSArray *data = [NSArray arrayWithContentsOfFile:path];
if (data) {
[array setArray:data];
}
[array addObject:#"My Task"];
BOOL iswritten = [array writeToFile:path atomically:YES];
if (!iswritten) {
NSLog(#"Failed");
}
[data release];
}
}
- (void)getFile:(id)sender {
NSString * original = #"Hello";
NSString * pass = #"123";
NSString * step = [NSString stringWithFormat:#"%#.%#", original, pass];
NSString * file = [NSString stringWithFormat:#"%#.plist", step];
NSString *path = pathPlist(file);
NSMutableArray *array = [[NSMutableArray alloc] init];
if (path) {
NSArray *data = [NSArray arrayWithContentsOfFile:path];
if (data) {
[array setArray:data];
}
}
NSLog(#"%#", array);
}
Note: The var array holds the data from the filename(username.password.plist)
I am doing an iPad app, were i will have UITabelview and a Button and UiTextview in same screen. My task is that if i select some row in UITableview and press button the text has to be appeared on the UITextview.
I filled few methods but it didn't work can any one let me know what exactly i can do to complete this task successfully.
Please find my code below for your reference...it may help you to explain my problem.
#import <UIKit/UIKit.h>
#import "table1.h"
#import "textView.h"
#interface searchOne : UIViewController
{
IBOutlet UITableView *firstTable;
table1 *tableOne;
textView * text1;
int row;
}
#property(nonatomic,retain)IBOutlet UIButton * search;
#property (nonatomic,retain) IBOutlet UITextView *txt;
#property(nonatomic, assign) int row;
-(IBAction)resPage:(id)sender;
#end
#import "searchOne.h"
#import "textView.h"
#implementation searchOne
#synthesize search;
#synthesize txt, row;
- (void)viewDidLoad {
[super viewDidLoad];
if (tableOne == nil) {
tableOne = [[table1 alloc] init];
}
[firstTable setDataSource:tableOne];
tableOne.view = tableOne.tableView;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
row = [indexPath row];
}
-(IBAction)resPage:(id)sender{
NSString *str = txt.text;
row = [str intValue];
NSLog(#"get clicked");
self.view =txt;
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// [self setTxt:nil];
[super viewDidUnload];
}
#end
DB:
#import <Foundation/Foundation.h>
#interface db : NSObject{
NSInteger ID;
NSString * name;
}
#property (nonatomic, retain) NSString * name;
#property(nonatomic, readwrite) NSInteger ID;
-(id)initWithID: (NSInteger)i andName:(NSString *)n;
#end
#implementation db
#synthesize name,ID;
-(id)initWithID: (NSInteger)i andName:(NSString *)n{
self=[super init];
if(self)
{
self.ID = i;
self.name = n;
}
return self;
}
#end
Tabel view:
#import <UIKit/UIKit.h>
#import "sqlite3.h"
#import "db.h"
#interface table1 : UITableViewController<UITableViewDataSource>{
NSString *databaseName;
NSString * databasePath;
NSMutableArray * tableOne;
}
#property(nonatomic, retain) NSMutableArray * tableOne;
-(void)checkAndCreateDatabase;
-(void)readDataFromDatabase;
#end
#import "table1.h"
#import "db.h"
#implementation table1
#synthesize tableTwo;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
databaseName=#"nobel10.db";
NSArray *documentPaths= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDir = [documentPaths objectAtIndex:0];
databasePath=[documentDir stringByAppendingPathComponent:databaseName];
[self checkAndCreateDatabase];
[self readDataFromDatabase];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - TableView Data Source methods
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [tableTwo count]; }
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell= nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"mycell"];
if (cell == nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"mycell"];}
db * temp =(db *)[self.tableTwo objectAtIndex:indexPath.row];
cell.textLabel.text=temp.name;
return cell;
}
-(void)checkAndCreateDatabase{
BOOL success;
NSFileManager *fileManager=[NSFileManager defaultManager];
success=[fileManager fileExistsAtPath:databasePath];
if(success)
return;
NSString *databasePathFromApp = [[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
-(void)readDataFromDatabase{
sqlite3 *database;
tableTwo=[[NSMutableArray alloc]init];
if(sqlite3_open([databasePath UTF8String], &database)== SQLITE_OK){
const char *sqlStatement = "SELECT * FROM country";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL)==SQLITE_OK){
while (sqlite3_step(compiledStatement)==SQLITE_ROW) {
NSInteger pId = sqlite3_column_int(compiledStatement, 0);
NSString *stringName=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
db *info =[[db alloc]initWithID:pId andName:stringName];
[tableTwo addObject:info];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
#end
UITextView:
#import <UIKit/UIKit.h>
#import "sqlite3.h"
#import "db.h"
#interface textView : UIViewController<UITextViewDelegate>{
NSString *databaseName;
NSString * databasePath;
NSMutableArray *textOne;
NSString *description;
}
#property(nonatomic, retain) NSMutableArray *textOne;
#property (nonatomic, retain) NSString *description;
-(void)checkAndCreateDatabase;
-(void)readDataFromDatabase;
-(id)initWithDescription:(NSString *)d;
#end
#import "textView.h"
#implementation textView
#synthesize textOne, description;;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
databaseName=#"nobel10.db";
NSArray *documentPaths= NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentDir = [documentPaths objectAtIndex:0];
databasePath=[documentDir stringByAppendingPathComponent:databaseName];
[self checkAndCreateDatabase];
[self readDataFromDatabase];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
#pragma mark - TableView Data Source methods
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
-(void)checkAndCreateDatabase{
BOOL success;
NSFileManager *fileManager=[NSFileManager defaultManager];
success=[fileManager fileExistsAtPath:databasePath];
if(success)
return;
NSString *databasePathFromApp = [[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
-(void)readDataFromDatabase{
sqlite3 *database;
textOne=[[NSMutableArray alloc]init];
if(sqlite3_open([databasePath UTF8String], &database)== SQLITE_OK){
const char *sqlStatement = "SELECT name,item_country.id,text.item FROM country,item_country,text WHERE country.name ='India' AND country.id = item_country.id AND text.item =item_country.item ";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL)==SQLITE_OK){
while (sqlite3_step(compiledStatement)==SQLITE_ROW) {
NSInteger pId = sqlite3_column_int(compiledStatement, 0);
NSString *stringName=[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
db *info =[[db alloc]initWithID:pId andName:stringName];
[textOne addObject:info];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
-(id)initWithDescription:(NSString *)d{
self.description = d;
return self;
}
#end
PLease help me i am new to iPad development and struck here..
A quick and dirty way is just to remove the UITextView, and add it back in when you select the row. See if that works.
I realize this is not the question you asked, but depending on your needs, you might want to use Core Data instead. It abstracts the .sqlite database from you and does some pretty cool things in terms of memory usage, modelling objects and relationships and so on.
I've been learning Objective C and the iPhone SDK gradually, and my current project involves building an application that stores numerical data (sports data). This is primarily for learning purposes, as there are multiple apps that do the same thing. Anyway, I've hit a bit of a snag. My intention is to have a list of players stored in a table and allow the user to add additional players.
At the moment, I have a button that when pressed, "Ninjas" will be added to the table. I've also enabled deleting in the table. Unfortunately, I can't seem to figure out how to save and load the data from a plist. I followed various tutorials and guides, but I can't figure out what's happening. My suspicion is I am loading the data from an empty array and adding to that array, but the array involving the data is a separate array from the plist. Unfortunately, I am a bit lost beyond that.
The data in my array is erased whenever I switch views. However, I've noticed that the data remains if I leave and come back, but not if I leave for a considerable amount of time, leave and restart the iphone, etc. This seems to occur even for apps that I have not worked on saving. Is this just a function of the iPhone holding onto data in case a user accidentally exits a program?
Hopefully I explained my issue somewhat tangibly. TL:DR version: I want to add data to an array, save it to a plist, and reload the data from the plist whenever the array is present on the screen. Code below is attempting to accomplish this, but it isn't succeeding.
Thanks
#import "RootViewController.h"
#import "NewPlayer.h"
#import "OptionsMenu.h"
#implementation RootViewController
#synthesize createdPlayers;
#synthesize listOfPlayers;
-(NSString *) pathOfFile{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolder = [paths objectAtIndex:0];
return [documentFolder stringByAppendingFormat:#"myfile.plist"];
}
-(void)applicationWillTerminate:(NSNotification*)notification{
NSMutableArray *array = [[NSMutableArray alloc]init];
[array writeToFile: [self pathOfFile] atomically:YES];
}
- (void)viewDidLoad
{
NSString *filePath = [self pathOfFile];
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
listOfPlayers.array = [array objectAtIndex:0];
[array release];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app];
[super viewDidLoad];
listOfPlayers = [[NSMutableArray alloc] init];
}
-(IBAction)AddButtonAction:(id)sender{
[listOfPlayers addObject:#"Ninjas"];
[createdPlayers reloadData];
}
-(IBAction)switchView:(id)sender{
OptionsMenu *second = [[OptionsMenu alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated:YES];
}
-(IBAction)newView:(id)sender{
NewPlayer *second = [[NewPlayer alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:second animated: YES];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [listOfPlayers count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:15];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.textAlignment = UITextAlignmentCenter;
NSString *cellValue = [listOfPlayers objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSLog(#"delete section: %d rol: %d", [indexPath indexAtPosition:0], [indexPath indexAtPosition:1]);
[listOfPlayers removeObjectAtIndex:[indexPath indexAtPosition:1]];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert)
{
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
-(void)tableView:(UITableView *)listOfPlayers moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath{
}
-(void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc{
[createdPlayers release];
[listOfPlayers release];
[super dealloc];
}
#end
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView* createdPlayers;
IBOutlet UIButton* superCat;
NSMutableArray *listOfPlayers;
}
#property(nonatomic, retain) IBOutlet NSObject *listOfPlayers;
-(NSString *) pathOfFile;
-(void)applicationWillTerminate:(NSNotification*)notification;
-(IBAction)AddButtonAction:(id)sender;
-(IBAction)switchView:(id)sender;
-(IBAction)newView:(id)sender;
#property (nonatomic, retain) UITableView* createdPlayers;
#end
Code update 20th Dec:
-(NSString *) pathOfFile{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolder = [paths objectAtIndex:0];
return [documentFolder stringByAppendingFormat:#"myfile.plist"];
}
-(void)applicationWillTerminate:(NSNotification*)notification
{
[self.listOfPlayers writeToFile:[self pathOfFile] atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}
- (void)viewDidLoad
{
self.listOfPlayers = [[NSMutableArray alloc] init];
NSString *filePath = [self pathOfFile];
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
self.listOfPlayers = array;
[array release];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:app];
[super viewDidLoad];
}
I don't know plist. But you can try use NSData
NSArray *array;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
//Write data
[data writeToFile:filePath atomically:YES];
//Read data
NSFileManager *fileManager = [NSFileManager defaultManager];
NSData *oldData = [fileManager contentsAtPath:filePath];
NSArray *newArray = [NSKeyedUnarchiver unarchiveObjectWithData:oldData]
Welcome to the world of iOS programming. It's a lot of fun, but it can be frustrating, just as programming in any language can be. I feel your pain.
There are a number of things that I see:
In viewDidLoad, it appears that your code to read your file into an array is okay, but then it appears as if you're trying to assign only the first row of this array to your listOfPlayers. Try:
self.listOfPlayers = array;
array is an array, and so is your listOfPlayers. Also, using self will ensure that the synthesized setter is used, thus retaining your listOfPlayers when you release array.
In applicationWillTerminate, I believe you wish to write your listOfPlayers to a file, but what you are actually doing is allocating and initializing an empty array, and writing THAT to your file. Try:
-(void)applicationWillTerminate:(NSNotification*)notification
{
[self.listOfPlayers writeToFile: [self pathOfFile] atomically:YES];
}
I hope this helps!
There seems something wrong in your viewDidLoad
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSArray *array = [[NSArray alloc]initWithContentsOfFile:filePath];
listOfPlayers.array = [array objectAtIndex:0];
.
.
}
.
.
.
listOfPlayers = [[NSMutableArray alloc] init];
You are accessing listOfPlayers before ever allocating it.
listOfPlayers.array is wrong as well
I have declared a NSMutableArray and I populated it with information from the database. The table displays information well. But when I scroll down, the application exits. Seems like its loosing the pointer to the array.
Here is the code for declaration of the array:
#interface RootViewController : UITableViewController <CLLocationManagerDelegate> {
sqlite3 *database;
NSMutableArray *storeList;
CLLocationManager *locationManager;
CLLocation *startingPoint;
}
#property (nonatomic, retain) NSMutableArray *storeList;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) CLLocation *startingPoint;
- (void) createCopyOfDatabaseIfNeeded;
- (void) initializeStoreList;
- (void) getDistanceFromUserLocation;
Here I am initializing the array with object of type StoreInfo:
- (void) initializeStoreList{
self.storeList = [[NSMutableArray alloc] init];
//database is stored in the application bundle.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:kFileName];
if (sqlite3_open([dbPath UTF8String], &database)== SQLITE_OK) {
const char *sql = "select id, storename, ratings, lattitude, longitude from storeinformation";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
NSInteger *_pk = (NSInteger *) sqlite3_column_int(statement, 0);
NSString *_storeName = [NSString stringWithUTF8String:(char*) sqlite3_column_text(statement, 1)];
NSString *_ratings = [NSString stringWithUTF8String:(char*) sqlite3_column_text(statement, 2)];
double _lattitude = [[NSString stringWithUTF8String:(char*) sqlite3_column_text(statement, 3)] doubleValue];
double _longitude = [[NSString stringWithUTF8String:(char*) sqlite3_column_text(statement, 4)] doubleValue];
StoreInfo *si = [[StoreInfo alloc] initWithBasicInformation:_pk storeName:_storeName ratings:_ratings lattitude:_lattitude longitude:_longitude];
[self.storeList addObject:si];
[si release];
}
}
sqlite3_finalize(statement);
} else {
sqlite3_close(database);
NSAssert1(0,#"Failed to open the database with message '%s'.", sqlite3_errmsg(database));
}
}
here is the constructor for StoreInfo object
-(id)initWithBasicInformation:(NSInteger *)_pk storeName:(NSString *) _storeName ratings:(NSString *) _ratings lattitude:(double) _lattitude longitude:(double) _longitude;
{
if (self = [super init]) {
self.primaryKey = _pk;
self.storeName = _storeName;
self.ratings = _ratings;
self.lattitude = _lattitude;
self.longitude = _longitude;
}
return self;
}
Here is the code for displaying the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
StoreInfo *si = (StoreInfo *)[self.storeList objectAtIndex:indexPath.row];
cell.textLabel.text = si.storeName;
return cell;
}
The table displays alright first. But when I scroll down, this even gets fired and somehow it is not able to find reference to the si.storeName.
I have spent hours trying to debug the issue. Any help is greatly appreciated.
First of all, how have you defined the property for the problematic field?
Is it retain?
Secondly, Can you access any other property in si?
And finally, I see that there is a memory leak in self.storeList = [[NSMutableArray alloc] init]; - the object is retained twice (in init and in the property setter)...