i went table view change content depend on SegmentIndex
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell
book *bok = (book *)[self.booktable objectAtIndex:indexPath.row];
NSArray *rowoftitle = [NSArray arrayWithObjects:bok.book_title, nil];
NSArray *rowofauth = [NSArray arrayWithObjects:bok.author_name, nil];
NSArray *rowofpub = [NSArray arrayWithObjects:bok.pub_name, nil];
//[cell setText:bok.book_title];
[tableView beginUpdates];
switch (segControl.selectedSegmentIndex)
{
case 0:
[tableView insertRowsAtIndexPaths:rowoftitle withRowAnimation:UITableViewRowAnimationTop];
//cell.textLabel.text =bok.book_title;
break;
case 1:
[tableView insertRowsAtIndexPaths:rowofauth withRowAnimation:UITableViewRowAnimationTop];
//[libraryTV reloadData];
//cell.textLabel.text =bok.author_name;
break;
case 2:
[tableView insertRowsAtIndexPaths:rowofpub withRowAnimation:UITableViewRowAnimationTop];
//cell.textLabel.text =bok.pub_name;
break;
default:
break;
}
[tableView endUpdates];
//return cell;
}
but when run it the expiation is happen :
'NSInvalidArgumentException', reason: '-[NSCFString row]: unrecognized
selector sent to instance 0x5d84f80
how resolve it.
One solution could be:
You will need to use a common datasource (in this code I am using dataSourceArray for this purpose, you will need to declare it in header file and alloc/init in viewDidLoad method.), which will be updated on changing the segment.
It will have following method.(for segment change event)
-(void)segmentSelected:(UISegmentedControl *)sender
{
switch (sender.selectedSegmentIndex)
{
case 0:
[self loadTitles];
break;
case 1:
[self loadAuthors];
break;
case 2:
[self loadPublishers];
break;
default:
break;
}
}
- (void) loadTitles
{
[self.dataSourceArray removeAllObjects];
for (Book *book in self.booktable)
{
[dataSourceArray addObject:book.book_title];
}
[<yourTableViewVariable> reloadData];
}
Similarly code for other methods loadAuthors and loadPublishers.
Now your numberOfRowsInSection method will be:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [dataSourceArray count];
}
and cellForRowAtIndexPath will be:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell
cell.textLabel.text = [dataSourceArray objectAtIndex:indexPath.row];
return cell;
}
Thanks
Changing content means setting properties of the cell from your data source based on the section. That's normal and Apple's docs on how to implement a UITableViewController cover it well. What you are doing is attempting to modify the structure of the table while the table is reloading. You absolutely cannot do that.
The table modification methods (e.g. insertRowsAtIndexPaths:withRowAnimation:) are meant to be called after you've modified the data model and want to update the table dynamically w/o reloading the entire table. These cannot be called inside any method used to construct the table or cells. tableView:cellForRowAtIndexPath: will end up being called by insertRowsAtIndePaths:... to construct the cells for the new rows.
in interface :
NSMutableArray *booktable;
NSMutableArray *sbook;
NSMutableArray *rowoflibrary;
NSString *databaseName;
NSString *databasePath;
IBOutlet UISegmentedControl *segControl;
IBOutlet UITableView *libraryTV;
IBOutlet UISearchBar *searchBar;
in implementation
- (void)viewDidLoad {
databaseName = #"MydataBase.db";
// 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
[self checkAndCreateDatabase];
[self readbookFromDatabase];
booktable = [[NSMutableArray alloc]init];
[booktable addObjectsFromArray:sbook];
rowoflibrary = [[NSMutableArray alloc] init];
[super viewDidLoad];}
-(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 = [NSFileManager defaultManager];
// 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 = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
[fileManager release];}
-(void) readbookFromDatabase {
// Setup the database object
sqlite3 *database;
// Init the staff Array
sbook = [[NSMutableArray alloc] init];
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement ="select book.title,author.auth_name ,publisher.pub_name , book.info from book ,author, publisher where book.auth_id = author.auth_id and book.pub_id = publisher.pub_id";
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
char * str = (char*)sqlite3_column_text(compiledStatement, 0);
if (str){
title = [NSString stringWithUTF8String:str];
}
else{
title =#" ";
}
char * str1 = (char*)sqlite3_column_text(compiledStatement, 1);
if (str1){
authorName = [NSString stringWithUTF8String:str1];
}
else{
authorName =#" ";
}
char * str2 = (char*)sqlite3_column_text(compiledStatement, 2);
if (str2){
pubName = [NSString stringWithUTF8String:str2];
}
else{
pubName =#" ";
}
char * str3 = (char*)sqlite3_column_text(compiledStatement,3);
if (str3){
info = [NSString stringWithUTF8String:str3];
}
else{
info =#" ";
}
// Create a new book object with the data from the database
book *bok = [[book alloc] initWithbook:title autname:authorName pubname:pubName infobook:info];
// Add the book object to the staff Array
[sbook addObject:bok];
[bok release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);}
-(void)segmentSelected:(UISegmentedControl *)sender{
switch (sender.selectedSegmentIndex) {
case 0:
[self loadTitles];
break;
case 1:
[self loadAuthors];
break;
case 2:
[self loadPublishers];
break;
default:
break; }}
- (void) loadTitles
{
[rowoflibrary removeAllObjects];
for (book *bok in self.booktable)
{
[rowoflibrary addObject:bok.book_title];
}
[libraryTV reloadData];
}
(void) loadAuthors
{
[rowoflibrary removeAllObjects];
for (book *bok in self.booktable)
{
[rowoflibrary addObject:bok.author_name];
}
[libraryTV reloadData];
}
(void) loadPublishers
{
[rowoflibrary removeAllObjects];
for (book *bok in self.booktable)
{
[rowoflibrary addObject:bok.pub_name];
}
[libraryTV reloadData];
}
pragma mark -
pragma mark Table view data source
(NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [rowoflibrary count];
}
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell
cell.textLabel.text = [rowoflibrary objectAtIndex:indexPath.row];
return cell;
}
when run it it is empty table view
Related
I am trying to do a search in a UITableview. I have implemented the UISearchDisplayDelegate, UISearchBarDelegate method at the correct way. This is how my cellForRowAtIndexPath looks like.
- (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];
}
if (tableView == self.searchDisplayController.searchResultsTableView){
Contact *contact = [self.filteredListContent objectAtIndex:indexPath.row];
NSString *text = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
NSLog(#"CellForRowAtIndexPath contact text is %#",text);
cell.textLabel.text = text;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}else{
NSString *alphabet = [firstIndex objectAtIndex:[indexPath section]];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF.name beginswith[c] %#",alphabet];
NSArray *contacts = [listContent filteredArrayUsingPredicate:predicate];
Contact *contact = [contacts objectAtIndex:indexPath.row];
NSString *text = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
cell.textLabel.text = text;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
}
return cell;
}
And this is my filterContentForSearchText method
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
[self.filteredListContent removeAllObjects]; // First clear the filtered array.
for (Contact *contact in listContent)
{
NSString *searchString = [NSString stringWithFormat:#"%# %#",contact.name,contact.firstName];
NSRange range = [searchString rangeOfString:searchText options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
[self.filteredListContent addObject:contact];
[self.searchDisplayController.searchResultsTableView reloadData];
}
}
}
The strange thing is. In my cellForRowAtIndexPath it returns me the correct data. But the tableview itselfs keeps given me the NO RESULTS label.
Any help with this?
Follow this tutorial how-to-add-search-bar-uitableview ..
Just see the method cellForRowAtIndexPath: in which how to set the search array when user searched record from UISearchBar...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"RecipeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
if (tableView == self.searchDisplayController.searchResultsTableView) {
cell.textLabel.text = [searchResults objectAtIndex:indexPath.row];
} else {
cell.textLabel.text = [recipes objectAtIndex:indexPath.row];
}
return cell;
}
Use an array to show data in table(showDataArray)
Use an array to store all input values(dataArray)
Use showDataArray to populate your table always
In the searchfield when charecter range changes call a method to filter the data using predicate from dataArray
Save the value to showDataArray
Call for table reloadData
First add UISearchBar on top of UITabelView documentation
And then Take Two NSMutableArray and add one array to another array in ViewDidLoad method such like,
self.listOfTemArray = [[NSMutableArray alloc] init]; // array no - 1
self.ItemOfMainArray = [[NSMutableArray alloc] initWithObjects:#"YorArrayList", nil]; // array no - 2
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray]; // add 2array to 1 array
And Write following delegate Method of UISearchBar
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchText
{
NSString *name = #"";
NSString *firstLetter = #"";
if (self.listOfTemArray.count > 0)
[self.listOfTemArray removeAllObjects];
if ([searchText length] > 0)
{
for (int i = 0; i < [self.ItemOfMainArray count] ; i = i+1)
{
name = [self.ItemOfMainArray objectAtIndex:i];
if (name.length >= searchText.length)
{
firstLetter = [name substringWithRange:NSMakeRange(0, [searchText length])];
//NSLog(#"%#",firstLetter);
if( [firstLetter caseInsensitiveCompare:searchText] == NSOrderedSame )
{
// strings are equal except for possibly case
[self.listOfTemArray addObject: [self.ItemOfMainArray objectAtIndex:i]];
NSLog(#"=========> %#",self.listOfTemArray);
}
}
}
}
else
{
[self.listOfTemArray addObjectsFromArray:self.ItemOfMainArray ];
}
[self.tblView reloadData];
}
And Write in cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Foobar"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foobar"];
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.textLabel.textColor = [UIColor blackColor];
}
cell.textLabel.text = [self.listOfTemArray objectAtIndex: indexPath.row];
return cell;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to Get Data from a PList into UITableView?
I have a plist with Dictionary and numbers of strings per dictionary.show into the url below.and this list of items is in thousands in the plist.
Now want to display these list into the tableview
.
now how can i display this plist into the UITableView
what I am trying is:
- (id)readPlist:(NSString *)fileName
{
NSString *error;
NSPropertyListFormat format;
id plist;
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:#"A" ofType:#"plist"];
dic =[NSDictionary dictionaryWithContentsOfFile:localizedPath];
plist = [NSPropertyListSerialization propertyListFromData:dic mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!plist) {
NSLog(#"Error reading plist from file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]);
[error release];
}
return plist;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
dict =[self readPlist:#"A"];
return dict.allKeys.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
dict = [self readPlist:#"A"];
key = [dict.allKeys objectAtIndex:section];
return [[dict valueForKey:key] count];
}
- (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];
}
cell.textLabel.text = [[dict objectForKey:key] objectAtIndex:indexPath.row];
return cell;
}
UPDATE 2: You need to set the delegate and datasource for your tableView in your xib or ViewController.
In your ViewController.h file
#interface ViewController:UIViewController <UITableViewDelegate, UITableDataSource>
Try this code which I have written for you.
- (void)viewDidLoad {
tableView.delegate = self;
tableView.dataSource = self;
NSString *path = [[NSBundle mainBundle] pathForResource:#"Filename" ofType:#"plist"];
NSArray *contentArray = [NSArray arrayWithContentsOfFile:path];
// Having outlet for tableArray variable.
tableArray = [[NSMutableArray alloc]initWithArray:contentArray copyItems:YES];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [tableArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// In your case dictionary contains strings with keys and values. The below line returns dictionary only. not array..
NSDictionary *dictionary = [tableArray objectAtIndex:section];
return dictionary.allKeys.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
}
NSDictionary *dictionary = [tableArray objectAtIndex:indexPath.section];
NSArray *keysArray = dictionary.allKeys;
// This below line display the key in textLabel
cell.textLabel.text = [keysArray objectAtIndex:indexPath.row];
// Below line will display the value of a key in detailTextLabel.
cell.detailTextLabel.text = [dictionary valueForKey:[keysArray objectAtIndex:indexPath.row]];
return cell;
}
UPDATE 2: After I have seen your plist in my MAC, I have found out that we are working with array of dictionaries in your A.plist.
So I found there is a bug in our code itself. Not in the plist file and you can use your 8000 data plist too.. Its working too. I have checked out totally. Now you can get the above Code and start work with.
store Plist data in array
- (id)readPlist:(NSString *)fileName
{
NSString *error;
NSPropertyListFormat format;
id plist;
NSString *localizedPath = [[NSBundle mainBundle] pathForResource:#"A" ofType:#"plist"];
// declare your array in .h file
array = [NSArray arrayWithContentsOfFile:localizedPath];
plist = [NSPropertyListSerialization propertyListFromData:dic mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!plist) {
NSLog(#"Error reading plist from file '%s', error = '%s'", [localizedPath UTF8String], [error UTF8String]);
[error release];
}
return plist;
}
and then write it in table
- (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];
}
cell.textLabel.text = [array objectAtIndex:indexPath.row] valueForKey:#"keyname"];;
return cell;
}
i have a SQL file where 5 different type of data is stored. I am adding this data in a dictionary specified with keys. and then i am adding this dictionary to tableData array as a dataSource for table and searchBar. But it is not searching anything.
adding code below
- (void)viewDidLoad {
[super viewDidLoad];
dataSource =[[NSMutableArray alloc] init];
tableData = [[NSMutableArray alloc]init];
searchedData = [[NSMutableArray alloc]init];
NSString *query = [NSString stringWithFormat:#"SELECT * FROM Vegetables"];
SQLite *sqlObj1 = [[SQLite alloc] initWithSQLFile:#"ShoppersWorld.sqlite"];
[sqlObj1 openDb];
[sqlObj1 readDb:query];
// [query release];
for (int i=0; i<[dataSource count]; i++) {
NSLog(#"data:%#",[dataSource objectAtIndex:i]);
}
while ([sqlObj1 hasNextRow])
{
NSString *name=[sqlObj1 getColumn:1 type:#"text"];
NSString *price=[sqlObj1 getColumn:2 type:#"text"];
NSString *quantity=[sqlObj1 getColumn:3 type:#"text"];
NSString *unit=[sqlObj1 getColumn:4 type:#"text"];
NSString *total=[sqlObj1 getColumn:5 type:#"text"];
dict = [[NSMutableDictionary alloc] initWithObjectsAndKeys: name,#"nameOfVegetables",
price,#"priceOfVegetables",
quantity,#"quantityOfVegetables",
unit,#"unitOfVegetables",
total,#"totalPriceOfVegetables",nil];
//NSLog(#"results:%# %#",dict);
[dataSource addObject:dict];
}
[tableData addObjectsFromArray:dataSource];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
// Set up the cell...
// Configure the cell.
else {
cell.productLbl.text= [NSString stringWithFormat:#"%#",[[tableData objectAtIndex:indexPath.row]objectForKey:#"nameOfVegetables"] ];
cell.bPriceLbl.text = [NSString stringWithFormat:#"Rs %d/Kg",
[[[tableData objectAtIndex:indexPath.row] objectForKey:#"priceOfVegetables"] intValue]];
cell.qtyLbl.text = [NSString stringWithFormat:#"QTY: %# %#",[[tableData objectAtIndex:indexPath.row]
objectForKey:#"quantityOfVegetables"],[[tableData objectAtIndex:indexPath.row] objectForKey:#"unitOfVegetables"]] ;
cell.tPriceLbl.text = [NSString stringWithFormat:#"TOTAL: %#",[[tableData objectAtIndex:indexPath.row]
objectForKey:#"totalPriceOfVegetables"]];
}
return cell;
}
#pragma search operations
- (IBAction)search:(id)sender{
sBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0,40,320,30)];
sBar.delegate = self;
[self.view addSubview:sBar];
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
// only show the status bar’s cancel button while in edit mode
[sBar setShowsCancelButton:YES animated:YES];
sBar.autocorrectionType = UITextAutocorrectionTypeNo;
// flush the previous search content
[tableData removeAllObjects];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar{
[sBar setShowsCancelButton:NO animated:YES];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
[tableData removeAllObjects];// remove all data that belongs to previous search
if([searchText isEqualToString:#""] || searchText==nil){
[tableview reloadData];
return;
}
NSInteger counter = 0;
for(NSString *name in dataSource)
for (int i = 0; i < [dataSource count]; i++)
{
NSMutableDictionary *temp = (NSMutableDictionary*) [dataSource objectAtIndex:i];
NSString *name = [NSString stringWithFormat:#"%#", [temp valueForKey:#"nameOfVegetables"]];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSRange r = [name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound)
{
if(r.location== 0)//that is we are checking only the start of the names.
{
[tableData addObject:name];
}
}
counter++;
[pool release];
}
[tableview reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar{
sBar.hidden= YES;
// if a valid search was entered but the user wanted to cancel, bring back the main list content
[tableData removeAllObjects];
[tableData addObjectsFromArray:dataSource];
#try{
[tableview reloadData];
}
#catch(NSException *e){
}
[sBar resignFirstResponder];
sBar.text = #"";
}
In search delegate methods you manipulate not with searchedData but tableData array. As these name suggest, array searchedData is supposed to store filtered data.
By the way, your approach to use sqlite for data source and absorbing all database into array is wrong. In cellForRowAtIndexPath read from sqlite database only data you need at the moment.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// load from sqlite only data for this cell.
// Use searchBar.text with sqlite's LIKE to filter data from database
NSUInteger row = [indexPath row];
static NSString *CellIdentifier = #"SignsCellIdentifier";
UITableViewCell *cell = [table dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
NSString *sql = [NSString stringWithFormat:#"SELECT fieldNameFromTable FROM TableName WHERE FieldToLookForIn LIKE \"%%%#%%\" LIMIT 1 OFFSET %u", searchBar.text ? searchBar.text : #"", row];
sqlite3_stmt *stmt;
int res = sqlite3_prepare_v2(database, [sql UTF8String], -1, &stmt, NULL);
if (res != SQLITE_OK) {
NSLog(#"sqlite3_prepare_v2() failed"];
return nil;
}
if (sqlite3_step(stmt) == SQLITE_ROW) {
const unsigned char *name = sqlite3_column_text(stmt, 0);
cell.text = [NSString stringWithUTF8String:(const char*)name];
}
sqlite3_finalize(stmt);
return cell;
}
How to apply search in this approach? In textDidChange do nothing but call [tableView reloadData]. And in cellForRowAtIndexPath load data with sqlite LIKE using searchBar.text as search term. So reloadData will load only filtered records. searchBarSearchButtonClicked will call only resignFirstResponder of it's caller, removing keyboard off screen. It doesn't need to do anything more because search is already done. searchBarCancelButtonClicked will set text property of it's caller to nil, call reload data and again call resignFirstResponder.
- (void)searchBarCancelButtonClicked:(UISearchBar *)s {
s.text = nil;
[tableView reloadData];
[s resignFirstResponder];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)s {
// search is already done
[s resignFirstResponder];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[tableView reloadData];
}
numberOfRowsInSection should also request db with the same SELECT as in cellForRowAtIndexPath, but with SELECT COUNT. Writing this method will be your homework)
I have a problem, I make a TabBAr application (with navigationbar), the bar bar is a list of favorits stored in an array.
My problem is that if I change ViewController and add object to array, when I come back to UITableView it isn't reloaded...
This is the class:
-
(void)viewDidLoad {
[super viewDidLoad];
[self readArgFromDatabaseSottoArgomenti];
[self VisualizzaPreferiti];
}
- (void)viewWillAppear:(BOOL)animated {
[self.tableView reloadData];
}
-(void) readArgFromDatabaseSottoArgomenti {
databasePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"ARGOMENTI.sqlite"];
sqlite3 *databaseDesc;
// Init the argoments Array
arraySottoArgomenti = [[NSMutableArray alloc] init];
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &databaseDesc) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
// const char *sqlStatement = "select * from DESCRIZIONE ";
const char *sqlStatement = [[NSString stringWithFormat:#"SELECT * from DESCRIZIONE ORDER BY id"] UTF8String];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(databaseDesc, 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 *aID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
NSString *aIDArgomento = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aDescrizione = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aTesto = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
// Create a new argoments object with the data from the database
ContenutoObjectDescrizione *contenutoSottoArgomenti = [[ContenutoObjectDescrizione alloc] initWithName:aID idArgomento:aIDArgomento descrizione:aDescrizione testo:aTesto];
[arraySottoArgomenti addObject:contenutoSottoArgomenti];
[contenutoSottoArgomenti release];
}
}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(databaseDesc);
}
- (void) VisualizzaPreferiti {
int i;
NSUserDefaults *userPref = [NSUserDefaults standardUserDefaults];
array = [userPref objectForKey:#"array"];
NSLog(#"Retain Count %d Numero ID Array %d",[array retainCount],[array count]);
NSMutableArray *arrayOggettoPreferito;
arrayOggettoPreferito = [[NSMutableArray alloc] init];
ContenutoObjectDescrizione *oggetto = [[ContenutoObjectDescrizione alloc] init];
for (oggetto in arraySottoArgomenti) {
for (i=0; i<[array count]; i++) {
if ([[array objectAtIndex:i] intValue] == [oggetto.id intValue]) {
[arrayOggettoPreferito addObject:oggetto];
NSLog(#"ID %# IDMateria %# Titolo %#",oggetto.id,oggetto.idArgomento,oggetto.descrizione);
}
}
}
listaPref = arrayOggettoPreferito;
arrayOggettoPreferito=nil;
[arrayOggettoPreferito release];
[oggetto release];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [listaPref 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];
}
ContenutoObjectDescrizione *oggettoCercato = [[ContenutoObjectDescrizione alloc] init];
oggettoCercato = [listaPref objectAtIndex:[indexPath row]];
cell.textLabel.text = oggettoCercato.descrizione;
NSLog(#"%#",oggettoCercato.descrizione);
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
TestoViewController *testoViewController = [[TestoViewController alloc] initWithNibName:#"TestoView" bundle:nil];
[self.navigationController pushViewController:testoViewController animated:YES];
ContenutoObjectDescrizione *oggettoCercato = [[ContenutoObjectDescrizione alloc] init];
oggettoCercato = [listaPref objectAtIndex:[indexPath row]];
testoViewController.idPreferito = oggettoCercato.id;
testoViewController.title = oggettoCercato.descrizione;
NSString *descrizioneWeb = oggettoCercato.testo;
NSString *path = [[NSBundle mainBundle] bundlePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[testoViewController.vistaWeb loadHTMLString:descrizioneWeb baseURL:baseURL];
[testoViewController release];
}
#pragma mark -
#pragma mark Memory management
- (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 {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
Simply calling reloadData doesn't make it do anything unless you update your datasource. In viewWillAppear, you will need to call VisualizzaPreferiti again before you call reloadData.
I have been trying to figure out what went wrong with this segment in my code. It was working fine for a normal UITableView, which has data extracted from a local database (results after clicking a button).
However, after I used this similar code for a UITableView that shows results of a search (I was trying to do a multiple category search but failed), there has been errors, differences between the selected row and the outcome or results on the TabBarViewController.
Following is my code for the linkage to the TabBarViewController.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
TabBarViewController *tabBarView = [[TabBarViewController alloc] initWithNibName:#"TabBarViewController" bundle:[NSBundle mainBundle]];
Attraction *att = [attractions objectAtIndex: indexPath.row];
tabBarView.attraction = att;
[self.navigationController presentModalViewController:tabBarView animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tabBarView release];
}
Here are my full codes for you to inspect:
-(void) checkAndCreateDatabase{
// Check if the SQL database has already been saved to the users phone, if not then copy it over
databaseName = #"funsg.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];
//NSLog([NSString stringWithFormat:#"GetData %#", databasePath]);
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 = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
success = [fileManager fileExistsAtPath:databasePath];
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
[fileManager release];
}
-(void)createEditableCopyOfDatabaseIfNeeded {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"abc.sql"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"abc.sql"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, #"Failed to create writable database file with message '%#'.", [error localizedDescription]);
}
}
-(void) readAttractionsFromDatabase {
[self checkAndCreateDatabase];
// Open the database
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = [[NSString stringWithFormat:#"select * from everything "] UTF8String];
//NSLog([NSString stringWithFormat:#"select * from everything"]);
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 *bus = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 0)];
NSString *desc = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *location = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *mrt = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSString *name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
NSString *image = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
NSString *type = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
NSString *carpark = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 7)];
// Create a new animal object with the data from the database
Attraction *att = [[Attraction alloc] initWithName:desc buses:bus add:location type:type mrt:mrt image:image name:name carpark:carpark];
if (attractions == NULL)
// There should not be a NULL name
NSLog(#"Null name!!");
else {
[attractions addObject:att];
// Apparently the addObject function in NSMutableArray does not
// keep a copy of our object, so, we can't release it.
//[name release];
[att release];
}
}
sqlite3_finalize(compiledStatement); // Cleanup the statement
}
else {
NSLog(#"Error retrieving data from database.");
}
sqlite3_close(database);
}
else {
NSLog(#"Error: Can't open database!");
}
}
-(void)viewDidLoad {
[super viewDidLoad];
attractions = [[NSMutableArray alloc] init];
searchedNames = [[NSMutableArray alloc] init];
[self loadData];
}
-(void) insertToDB :(Attraction*) att {
[self checkAndCreateDatabase];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
static sqlite3_stmt *compiledStatement;
sqlite3_exec(database, [[NSString stringWithFormat:#"INSERT INTO everything (Bus,Description,Location,MRT,Name,image,type,Carpark) SELECT '%#','%#','%#','%#', '%#', '%#', '%#', '%#' WHERE NOT EXISTS (SELECT 1 FROM everything WHERE Name = '%#');", att.buses,att.desc,att.add, att.mrt, att.name, att.image, att.type , att.carpark,att.name] UTF8String], NULL, NULL, NULL);
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
-(void) loadData {
//First fetch the data from the JSON
NSURL *url = nil;
NSString *querystring = [NSString stringWithFormat:#"http://mp15.bitproj1.com/testsearch.php"];
url = [NSURL URLWithString:querystring];
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url];
//NSLog(#"jsonreturn"); // Look at the console and you can see what the restults are
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSError *error = nil;
// In "real" code you should surround this with try and catch
self.data = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (data==nil){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Internet Connection" message:#"Unable to update the data." delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
else
{
self.rows =[data objectForKey:#"attractions"];
for (int i=0; i<[self.rows count]; i++) {
NSDictionary *dict = [rows objectAtIndex: i];
Attraction* a = [[Attraction alloc] initWithName:[dict objectForKey:#"Description"]
buses:[dict objectForKey:#"Bus"]
add:[dict objectForKey:#"Location"]
type:[dict objectForKey:#"type"]
mrt:[dict objectForKey:#"MRT"]
image:[dict objectForKey:#"image"]
name:[dict objectForKey:#"Name"]
carpark:[dict objectForKey:#"Carpark"]];
//Here we insert the data, when inserting we check for the duplicates. If the record already exists we do not insert. Code also must be optimized later
[self insertToDB:a];
}
}
[jsonreturn release];
[self readAttractionsFromDatabase];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return(1);
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return([searchedNames count]);
}
-(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];
}
NSString *cellText = [searchedNames objectAtIndex:indexPath.row];
[cell.textLabel setText:cellText];
return cell;
}
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
}
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[searchedNames removeAllObjects];// remove all data that belongs to previous search
if([searchText isEqualToString:#""] || searchText==nil) {
// Nothing to search, empty result.
[myTableView reloadData];
return;
}
for (NSString *att in attractions) {
Attraction* p = ((Attraction *)att);
NSRange r = [p.name rangeOfString:searchText options:NSCaseInsensitiveSearch];
if(r.location != NSNotFound) {
[searchedNames addObject:p.name];
}
}
[myTableView reloadData];
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
}
-(void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
TabBarViewController *tabBarView = [[TabBarViewController alloc] initWithNibName:#"TabBarViewController" bundle:[NSBundle mainBundle]];
Attraction *att = [attractions objectAtIndex: indexPath.row];
tabBarView.attraction = att;
[self.navigationController presentModalViewController:tabBarView animated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[tabBarView release];
}
-(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)viewDidUnload {
}
-(void)dealloc {
[data release];
[attractions release];
[super dealloc];
}
#end
Are you using two different array as datasource? If so, I think you are not retrieving the value from the correct array.
And also I can't understand the use of this code:
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES];
You can change that code as:
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
Edit
You are using two diff arrays searchedNames, attractions. There is the problem:
if(searching==YES)
{
//retrieve the values from searchedNames array
}
else
{
//retrieve the values from attractions array
}
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
searching=YES;
}
-(void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
searching=NO;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if(searching==YES)
return([searchedNames count]);
else
return [attractions count];
}
-(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];
}
NSString *cellText;
if(searching==YES)
cellText = [searchedNames objectAtIndex:indexPath.row];
else
cellText = [attractions objectAtIndex:indexPath.row];
[cell.textLabel setText:cellText];
return cell;
}