Xcode find table view section row on detail text label - objective-c

I have an index set up with my table and I am able to return the correct arrays for the textLabel.text according to the section header. My problem is I have an a separate array that i need to return in the detailTextLabel.text.
It just repeats in each section starting from the first index from the first section. For example:
A
Apple
apple
Alligator
alligator
B
Ball
apple
Bat
alligator
I've generated index characters and table headers. This is what I have to return the cell.
NSString *alphabet = [arrayIndex objectAtIndex:[indexPath section]];
//---get all of First array's beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *firstArray = [First filteredArrayUsingPredicate:predicate];
NSArray *secondArray = [Second filteredArrayUsingPredicate:predicate];
if ([FirstArray count]>0) {
//---extract the relevant state from the states object---
NSString *cellValue = [firstArray objectAtIndex:indexPath.row];
//<--This line throws and error assuming it is trying to find the first letter to return the detail text -->
NSString *cellValueA = [secondArray objectAtIndex:indexPath.row];
//Returns value from first section and row in all section//
//NSString *cellValueA = [Second objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
cell.detailTextLabel.text = cellValueA;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
How do I find the matching row to the First Array to return the correct index in the Second Array. Any help would be much appreciated. Thank You :-)
FULL CODE
-(void)loadSQL {
// Path to the database
NSString* dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"DATABASE_NAME.sqlite"];
NSLog(#"databasePath: %#",dbPath);
sqlite3 *database;
NSString *firstString;
NSString *secondString;
// Open the database
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK) {
NSString *querySQL = [NSString stringWithFormat:
#"SELECT * FROM songs WHERE items LIKE %# ", viewItems];
const char *sql = [querySQL UTF8String];
sqlite3_stmt *compiledStmt;
// Fetch all names
if (sqlite3_prepare_v2(database, sql, -1, &compiledStmt, NULL) == SQLITE_OK) {
// Append each name
while (sqlite3_step(compiledStmt) == SQLITE_ROW) {
const char* cFirst = (char*)sqlite3_column_text(compiledStmt, 2);
const char* cSecond = (char*)sqlite3_column_text(compiledStmt, 3);
if (cFirst == NULL)
// There should not be a NULL name
NSLog(#"Null name!!");
else {
firstString = [NSString stringWithUTF8String:cName];
secondString = [NSString stringWithUTF8String:cArtist];
[First addObject:firstString];
[Second addObject:secondString];
//[First release];
//[Second release];
}
}
sqlite3_finalize(compiledStmt); // Cleanup the statement
}
else {
NSLog(#"Error retrieving data from database.");
}
sqlite3_close(database);
}
else {
NSLog(#"Error: Can't open database!");
}
//Creating section with 1st letter of the First field//
for (int i=0; i<[First count]-1; i++){
//---get the first char of each state---
char alphabet = [[First objectAtIndex:i] characterAtIndex:0];
NSString *uniChar = [NSString stringWithFormat:#"%C", alphabet];
//---add each letter to the index array---
if (![arrayIndex containsObject:uniChar])
{
[arrayIndex addObject:uniChar];
}
}
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (searching)
return 1;
else
return [arrayIndex count];
}
//---set the title for each section---
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if (searching)
return nil;
else
return [arrayIndex objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (searching)
return([searchedFirst count]);
else{
//return([First count]);
NSString *alphabet = [songIndex objectAtIndex:section];
NSPredicate *predicate =[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *firstArray = [First filteredArrayUsingPredicate:predicate];
return [firstArray count];
}
}
//---set the index for the table---
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
if (searching) {
return nil;
}
return arrayIndex;
}
//return the cell info
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
if(searching) {
cell.textLabel.text = [searchedFirst objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [searchedSecond objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
else{
//---get the letter in the current section---
NSString *alphabet = [arrayIndex objectAtIndex:[indexPath section]];
//---get all states beginning with the letter---
NSPredicate *predicate =
[NSPredicate predicateWithFormat:#"SELF beginswith[c] %#", alphabet];
NSArray *firstArray = [First filteredArrayUsingPredicate:predicate];
NSArray *secondArray = [Second filteredArrayUsingPredicate:predicate];
if ([songArray count]>0) {
NSString *firstValue = [firstArray objectAtIndex:indexPath.row];
NSString *secondValue = [secondArray objectAtIndex:indexPath.row];
cell.textLabel.text = firtValue;
cell.detailTextLabel.text = secondValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
}
return cell;
}

I am not sure I understand what you need, but if you are looking for the index in the array of a given object, then you can use:
indexOfObject:
Returns the lowest index whose corresponding array value is equal to a given object.
- (NSUInteger)indexOfObject:(id)anObject
(ref)

Answering the question from comments about restructuring....
First, create a custom class:
// CellLabels.h
#import <Foundation/Foundation.h>
#interface CellLabels : NSObject
#property (nonatomic, copy) NSString *firstText;
#property (nonatomic, copy) NSString *secondText;
#end
//CellLabels.m
#import "CellLabels.h"
#implementation CellLabels
#synthesize firstText = _firstText;
#synthesize secondText = _secondText;
#end
Instead of First and Second, create and initialize one NSMutableArray called cellData. Replace...
[First addObject:firstString];
[Second addObject:secondString];
...with...
CellLabels *labels = [[CellLabels alloc] init];
labels.first = firstString;
labels.second = secondString;
[cellData addObject:labels];
Then, your array filtering works by comparing "SELF.firstText" and your array references work by using:
CellLabels *labels = [filteredArray objectAtIndex:indexPath.row];
cell.textLabel.text = labels.firstText;
cell.detailTextLabel.text = labels.secondText;
(OK, I didn't check to make sure all that compiled but it should give you the idea.)

Related

TableView section

I have an NSArray which includes a list of keys and this array comes out of a .plist.
At this moment i write this array in a UITableView, but this is not sorted and sectionized.
I want to sort this Array and want to have Sections in this UITableView which begins with the first character of each character in this Array.
As example:
Sectionname: "A"
Celltext: "Ahorn"
I hope you get it.
My Code now:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSArray * sections = [temp allValues];
NSUInteger *tablesections = [sections count];
return tablesections;
}
And:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
NSArray * values = [temp allValues];
[EingabeListe addObjectsFromArray:values];
char szDecryptetKey[256];
sleep(0.5);
NSString *cellValue = [values objectAtIndex:indexPath.row];
const char *cString = [cellValue cStringUsingEncoding:NSASCIIStringEncoding];
DecryptKey(cString, szDecryptetKey);
NSString *pnssDecryptetKey = [NSString stringWithFormat:#"%s",szDecryptetKey];
cell.textLabel.font = [UIFont systemFontOfSize:11.0];
cell.textLabel.text = pnssDecryptetKey;
return cell;
Thanks
I probably would not leave this in a single array. I would put it into a NSDictionary where each letter of the alphabet is a bucket to for each first letter of the alphabet (and a section). Then getting the contents of a single section would be as simple as looking up the first letter you want in the dictionary.
Start by sorting your array alphabetically. This has been asked a lot of times, but here's one answer
Next, iterate over the array and add it to a dictionary based on the first letter. Each "value" in dictionary would be an array, not just a single item. So the first time you'd get to a letter (say 'g') you'd create the "g" key in the dictionary and add an NSMutable array as the value.
As a side note, I didn't add code because this sounded like a homework assignment(of course I could be wrong). While I want to help, I wouldn't want to do it for you. That said, if it's unclear or you want more help, I'd be happy to provide).
I usually use the free Sensible TableView framework for these kind of apps. You literally just throw the array to the framework and it will automatically sort and create all the sections for you. Should take you a few minutes to implement so I recommend checking it out.
Hi thanks it works pretty fine.
But i can only see the first Character of my .plist.
I think the wrong line is this one:
NSString *cellValue = [values objectAtIndex:indexPath.row];
But here is my Code:
[super viewDidLoad];
self.EingabeListe = [NSMutableArray arrayWithCapacity:20];
NSIndexPath *indexPath = 0;
alphabet = [[NSArray alloc]initWithObjects:#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",
#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z",#"123",nil];
datasource = [[NSMutableDictionary alloc]initWithCapacity:[alphabet count]];
int m = 1;
int n = 0;
NSArray * values = [temp allValues];
int c = [values count];
//
char szDecryptetKey[256];
sleep(0.5);
while (m != 0) {
if ( n == c){
m = 0;
}else{
NSString *cellValue = [values objectAtIndex:indexPath.row];
const char *cString = [cellValue cStringUsingEncoding:NSASCIIStringEncoding];
NSString *pnssDecryptetKey = [NSString stringWithFormat:#"%s",szDecryptetKey];
[EingabeListe addObject:pnssDecryptetKey];
pnssDecryptetKey = 0;
}
n++;
}
for(int i = 0; i<[alphabet count]; i ++)
{
NSArray *filteredArray = [EingabeListe filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF BEGINSWITH[C] %#", [alphabet objectAtIndex:i]]];
if([filteredArray count]>0)
[datasource setObject:[filteredArray sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)] forKey:[alphabet objectAtIndex:i]]; // Dictionary containing sorted array of data with key as alphabets
}
}
In my .plist are some Test Keys and Values like this:
Value Key
sqq hi
zzz eg
egg bb
but in my.plist i can only see:
sqq
sqq
sqq
why?
For that you need to do modification in code; I will explain.
Steps:
Initialize the alphabets array and filter use source array based on the alphabets.
Now dataSource dictionary contains array of source data filtered by alphabets.
Now number of sections will the no. of array in the dictionary.
Load the data source array for each section from the datasource dictionary.
Initialize alphabets array and datasource array:
alphabet = [[NSArray alloc]initWithObjects:#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",
#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z",nil];
dataSource = [[NSMutableDictionary alloc]initWithCapacity:[alphabet count]];
sourceArray = [NSArray arrayWithObjects:#"Azz",#"ax",#"aje",#"B",#"C",#"Ca",#"D",#"DD",#"E",#"EE",#"F",#"G",#"F", nil];
Filter the source array and add the data into the dictionary with key values as alphabets:
for(int i = 0; i<[alphabet count]; i ++)
{
NSArray *filteredArray = [sourceArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF BEGINSWITH[C] %#", [alphabet objectAtIndex:i]]];
if([filteredArray count]>0)
dataSource setObject:[filteredArray sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)] forKey:[alphabet objectAtIndex:i]]; // Dictionary containing sorted array of data with key as alphabets
}
And you need to customize the number of sections and rows delegate methods. See the sample code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [[dataSource allKeys] count];
}
- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section
{
return [[dataSource allKeys] objectAtIndex:section];
}
Entire source code:
- (void)viewDidLoad
{
[super viewDidLoad];
alphabet = [[NSArray alloc]initWithObjects:#"A",#"B",#"C",#"D",#"E",#"F",#"G",#"H",#"I",#"J",#"K",
#"L",#"M",#"N",#"O",#"P",#"Q",#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z",nil];
dataSource = [[NSMutableDictionary alloc]initWithCapacity:[alphabet count]];
sourceArray = [NSArray arrayWithObjects:#"Azz",#"ax",#"aje",#"B",#"C",#"Ca",#"D",#"DD",#"E",#"EE",#"F",#"G",#"F", nil];
for(int i = 0; i<[alphabet count]; i ++)
{
NSArray *filteredArray = [sourceArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF BEGINSWITH[C] %#", [alphabet objectAtIndex:i]]];
if([filteredArray count]>0)
[dataSource setObject:[filteredArray sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)] forKey:[alphabet objectAtIndex:i]]; // Dictionary containing sorted array of data with key as alphabets
}
NSLog(#"Filtered Array %#", dataSource);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [[dataSource allKeys] count];
}
- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section
{
return [[dataSource allKeys] objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[dataSource objectForKey:[[dataSource allKeys] objectAtIndex:section]] count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
return 20;
}
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
originalSource = [dataSource objectForKey:[[dataSource allKeys] objectAtIndex:indexPath.section]];
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"%#",[originalSource objectAtIndex:indexPath.row]];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
Output will be like this:

cellForRowAtIndexPath getting the right data under each section

I'm stuck with a problem populating an UITableView.
I have got an NSMutableArray with customers. It looks like this:
customer
first letter="A"
customer name="Adwars Inc."
customer
first letter="A"
customer name="Amman Co."
customer
first letter="B"
customer name="Building Inc."
customer
first letter="C"
customer name="Computer Co."
So I've got an object customer, which separates me each customer. And i've got some keys for each object.
In my second NSArray i've got all my first letters, which appear in my customer data. It look like this:
A
B
C
D
G
J
M
S
Z
I was able to get my right section count and rows in section, but when i try to populate my table view it always look like this:
SCREENSHOT
HERE IS MY CODE
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"CustomerCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
}
for(int i = 0; i < [firstletters count]; i++)
{
if (indexPath.section == i) {
for(int count = 0 ;count < [customers count]; count++)
{
NSString *firstletter;
NSString *key;
key = [firstletters objectAtIndex:indexPath.section];
firstletter = [[customers objectAtIndex:count] objectForKey: #"FirstLetter"];
if ([key isEqualToString:firstletter]) {
cell.textLabel.text = [[customers objectAtIndex:count] objectForKey: #"S_NAME1"];
cell.detailTextLabel.text = [[customers objectAtIndex:count] objectForKey: #"s_town"];
}
}
}
}
return cell;
}
What do i have to do to make it work?
I know you have already accepted an answer, but I just wanted to offer another thought on how this might be done with data structured in a different way. If you had a dictionary where the keys were the first letter of your customers' names, and the values were the customer objects whose first letter was the same as the key, then you wouldn't have to do any looping (I don't know if you're still doing that in your solution). I made an example project (to see if this would work) that structures the data this way, except that my "objects" are just the names of companies rather than customer objects. In my table view controller I have:
- (void)viewDidLoad {
[super viewDidLoad];
self.companyDict = [NSMutableDictionary dictionary];
NSArray *aArray = [NSArray arrayWithObjects:#"Abercrombie & Fitch",#"Altera",#"Agilent",#"Allelix",#"Abbott Laboratories", nil];
NSArray *cArray = [NSArray arrayWithObjects:#"CocaCola",#"Continental",#"ConocoPhillips", nil];
NSArray *mArray = [NSArray arrayWithObjects:#"Myriad Genetics",#"Myrexis",#"Microsoft",#"McDonald's", nil];
NSArray *nArray = [NSArray arrayWithObjects:#"Nokia",#"NPS Pharmaceuticals",#"Norelco",#"Netflix",#"Nextel",#"Navistar International", nil];
[self.companyDict setValue:aArray forKey:#"A"];
[self.companyDict setValue:cArray forKey:#"C"];
[self.companyDict setValue:mArray forKey:#"M"];
[self.companyDict setValue:nArray forKey:#"N"];
self.keys = [[self.companyDict allKeys] sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.keys.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[self.companyDict valueForKey:[self.keys objectAtIndex:section]]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];
}
NSArray *theArray = [self.companyDict valueForKey:[self.keys objectAtIndex:indexPath.section]];
cell.textLabel.text = [theArray objectAtIndex:indexPath.row];
return cell;
}
For every cell, you're iterating through all the customers, repeatedly setting (and resetting) the textLabel and detailTextLabel for every customer whose first letter matches the current section (but you're not considering whether the index of that customer in that section matches the current indexPath.row or not). This means that in your code every cell will have the textLabel and detailTextLabel for the last customer whose first letter matches the current section's first letter.
Try this TableKit library.
This case the solution will be clean and elegant:
NSMutableDictionary* sectionMap = [NSMutableDictionary dictionaryWithCapacity:30];
for(NSDictionary* c in customers) {
NSString* firstLetter = [c objectForKey:#"FirstLetter"];
NSString* name = [c objectForKey:#"S_NAME1"];
NSString* town = [c objectForKey:#"s_town"];
TKSection* section = [sectionMap objectForKey:firstLetter];
if(!section) {
section = [TKSection sectionWithCells:nil];
section.headerTitle = firstLetter;
[sectionMap setObject:section forKey:firstLetter];
}
TKCell* cell = [TKStaticCell cellWithStyle:UITableViewCellStyleSubtitle text:name detailText:town];
[section addCell:cell];
}
self.sections = [sectionMap allValues];
TRY THIS (Copy and paste this code):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] init];
cell = nil;
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"CustomerCell"] autorelease];
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
}
for(int i = 0; i < [firstletters count]; i++) {
if (indexPath.section == i) {
for(int count = 0 ;count < [customers count]; count++) {
cell.textLabel.text = nil;
cell.detailTextLabel.text = nil;
NSString *firstletter = nil;
NSString *key = nil;
key = [firstletters objectAtIndex:indexPath.section];
firstletter = [[customers objectAtIndex:count] objectForKey: #"FirstLetter"];
if ([key isEqualToString:firstletter]) {
cell.textLabel.text = [[customers objectAtIndex:count] objectForKey: #"S_NAME1"];
cell.detailTextLabel.text = [[customers objectAtIndex:count] objectForKey: #"s_town"];
}
}
}
}
return cell;
}

iOS NSArray of NSDictionaries from SQLite in UITableView

I have been struggling for the last two days with this problem and I can't quite seem to figure it out. I have a SQlite database with the following structure.
it's a one to many relationship between List and List_Items
I access the database and create an object that is then added to a NSDictionary which is added to a NSArray. I do this twice, once for the List table and once for the List_Items.
Then I use the list Array to count the number of lists for my tableview rows, I then add them to the tableview.
The problem comes in when I get to the method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
I can't seem to figure out how to match up the records from Lists and List_Items to show the List Items that pertain to that list in a drill down tableview.
Specific code examples would be helpful as my mind is mush at this point :(
Here is the related code that I have up to my current Writersblock.
//#******************************************************#
// *******Start 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 = [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];
}
-(void)readItemsFromDatabase
{
// Setup the database object
sqlite3 *database;
// Init the Items Array
items = [[NSMutableArray alloc] init];
lists = [[NSMutableArray alloc] init];
//---------------### SELECT THE LISTS #####---------------//
// Open the database from the users filessytem
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"SQL Opened");
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "SELECT * from List";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aListName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aUserID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aListID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)];
NSLog(#"SQL Compiled");
// Create a new list object with the data from the database
List *list = [[List alloc] initWithlistName:(NSString *)aListName userID:(NSString *)aUserID listID:(NSString *)aListID];
listNames = [NSDictionary dictionaryWithObjectsAndKeys:list.listName,#"listName",list.listID,#"listID",list.listID,#"listID",nil];
// Add the Shopping object to the list Array
[lists addObject:listNames];
}
}
else { NSLog(#"Database Not Found");}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
//---------------### SELECT THE LIST_ITEMS #####---------------//
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
NSLog(#"SQL Opened");
// Setup the SQL Statement and compile it for faster access
const char *sqlStatement = "SELECT * from List_Items";
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK) {
// Loop through the results and add them to the array
while(sqlite3_step(compiledStatement) == SQLITE_ROW) {
// Read the data from the result row
NSString *aBrandName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 1)];
NSString *aItemName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 2)];
NSString *aItemQuantity = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 4)];
NSString *aImageUrl = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 5)];
NSString *aListID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 6)];
NSLog(#"SQL Compiled");
// Create a new items object with the data from the database
Shopping *shopping = [[Shopping alloc] initWithlistID:(NSString *)aListID brandName:(NSString *)aBrandName itemName:(NSString *)aItemName itemQuantity:(NSString *)aItemQuantity imageURL:(NSString *)aImageUrl];
itemList = [NSDictionary dictionaryWithObjectsAndKeys:shopping.listID,#"listID",shopping.brandName,#"brandName",shopping.itemName,#"itemName",shopping.itemQuantity,#"itemQuantity",shopping.imageURL,#"imageURL",nil];
// Add the Shopping object to the items Array
[items addObject:itemList];
}
}
else { NSLog(#"Database Not Found");}
// Release the compiled statement from memory
sqlite3_finalize(compiledStatement);
NSLog(#"%#",items);
NSLog(#"%#",lists);
}
sqlite3_close(database);
}
//#******************************************************#
// *******END Database*******
//#******************************************************#
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int rowcount;
rowcount = [lists count];
return rowcount;
}
-(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];
}
// Set up the cell...
NSString *cellValue = [[lists objectAtIndex:indexPath.row] objectForKey:#"listName"];
cell.textLabel.text = cellValue;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[lists objectAtIndex:indexPath.row] objectForKey:#"listID"] != NULL)
{
NSString *listIndex = [[lists objectAtIndex:indexPath.row] objectForKey:#"listID"];
int i = [listIndex intValue];
NSLog(#"indexPath: %d",i);
}
}
EDIT**********
The single Sql statement returns more than one Listname. This is an issue because I only need one of each list name.
So first of all, You're creating a List object and then creating an NSDictionary object that's pretty much the same as the List Object. Why? Why not just add the List object to the the Array. If you're not performing any functions on the properties in the List item, then don't use a List object at all, just put the fields directly in the NSDictionary.
Secondly, don't do two different SQL calls to get the info, use only one to get the List and the list_items for that list at the same time. Then if you're using your List object, add a NSMutableArray property call items, and add your listItems to that array. You can do the same thing in an NSDictionary, just add an NSMutableArray object for key items, then add the list_items to that array.
Now you'll be able to setup the tableview to do what you want.
Amended answer in response to comments below
Select * FROM List, List_Items WHERE List.list_id = List.list_id
Anyone interested this is how I ened up figuring it out.
I get the listID for the list then I make an array and loop through the list items an compair them against the listID. If they are the same as the listID I add them to the array and once it's finished with the for loop it adds the results to my dataobject protocol (to make it available to the next view) then I present a modal view controller and load the array from the dataobject. Once i'm done with the modal view I set the dataobject back to nil and Tada! it works.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[lists objectAtIndex:indexPath.row] objectForKey:#"listID"] != NULL)
{
[listTableView deselectRowAtIndexPath:indexPath animated:YES];
NSString *listIndex = [[lists objectAtIndex:indexPath.row] objectForKey:#"listID"];
NSMutableArray *itemArray = [[NSMutableArray alloc]init];
int i; int itemCount = [items count];
for (i = 0; i < itemCount; i++)
{
if ([[[items objectAtIndex:i] objectForKey:#"listID"] isEqual:listIndex])
{
[itemArray addObject:[items objectAtIndex:i]];
NSLog(#"Item Array:%#",itemArray);
}
}
if (i == itemCount)
{
AppDataObject* theDataObject = [self theAppDataObject];
theDataObject.itemArray = itemArray;
ItemView *temp = [[ItemView alloc] initWithNibName:#"ItemView" bundle:nil];
[self presentModalViewController: temp animated: YES];
}
}
}

Create index for UITableView from an NSArray

I've read that the best way of creating an index (the a-z at the side of a uitableview) is to set up an array of nsdictionaries, where each dictionary corresponds to a section, and a rowValue key contains an array of the rows.
NSDictionary
headerTitle => ‘A’
rowValues => {”Aardvark”, “Ape”, “Aquaman”}
NSDictionary
headerTitle => ‘B’
rowValues => {”Bat”, “Boot”, “Bubbles”} etc
But how can this be created from an array of all the row titles - {”Aardvark”, “Ape”, “Aquaman”, ”Bat”, “Boot”, “Bubbles”, "Cat", "Cabbage" etc} ...?
I recently had a similar objective and this is how I solved it. The advantage of this over Robin's solution is that it creates the index title array dynamically based on the content of your array and it won't include indices for empty sections (plus it's a little cleaner).
I created a category of NSMutableDictionary that takes an array of data as a parameter and returns an NSMutableDictionary (we'll call it indexDictionary and it should be an instance variable):
// if your data is static, you can call this in `viewDidLoad`
indexDictionary = [NSMutableDictionary createDictionaryForSectionIndex:arrayOfStrings];
The category method:
#implementation NSMutableDictionary (DictionaryForSectionIndex)
+(NSMutableDictionary *)createDictionaryForSectionIndex:(NSArray *)array
{
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (char firstChar = 'a'; firstChar <= 'z'; firstChar++)
{
//NSPredicates are fast
NSString *firstCharacter = [NSString stringWithFormat:#"%c", firstChar];
NSArray *content = [array filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF beginswith[cd] %#", firstCharacter]];
NSMutableArray *mutableContent = [NSMutableArray arrayWithArray:content];
if ([mutableContent count] > 0)
{
NSString *key = [firstCharacter uppercaseString];
[dict setObject:mutableContent forKey:key];
NSLog(#"%#: %u", key, [mutableContent count]);
}
}
return dict;
}
#end
/*
**Input:**
{"Aardvark", "Cabbage", "Boot", "Eggs", "Ape", "Aquaman", "Elephant", "Cat", "Bat", "Bubbles"}
**Output:**
NSMutableDictionary
key => 'A'
object => {"Aardvark", "Ape", "Aquaman"}
key => 'B'
object => {"Bat", "Boot", "Bubbles"}
key => 'C'
object => {"Cat", "Cabbage"}
key => 'E'
object => {"Elephant", "Eggs"}
*/
Then I create an NSArray instance variable to sort and store all the keys from indexDictionary:
// this line should follow the creation of `indexDictionary`
sortedKeys = [[indexDictionary allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
// Output, in this case, is {'A', 'B', 'C', 'E'}
You now have everything you need to set up the index for your table. Implement the following methods (if something isn't self explanatory, just let me know):
//this code assumes `sortedKeys` is not empty
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return ([sortedKeys count]);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *key = [sortedKeys objectAtIndex:section];
return [[indexDictionary valueForKey:key] count];
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return ([sortedKeys objectAtIndex:section]);
}
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return sortedKeys;
}
-(NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
return index;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// preceding code...
NSString *key = [sortedKeys objectAtIndex:indexPath.section];
NSArray *array = [indexDictionary objectForKey:key];
NSString *yourString = [array objectAtIndex:indexPath.row];
cell.textLabel.text = yourString;
// following code...
}
The result is a table with an index that skips letters that have no associated data.
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *temp = [[NSMutableArray alloc] init];
NSMutableArray *temp2 = [[NSMutableArray alloc] init];
for(int i = 0; i < tableListArray.count; i++)
{
NSString *string = [tableListArray objectAtIndex:i];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:string forKey:#"Name"];
[dict setObject:[NSNumber numberWithInt:i] forKey:#"ID"];
NSString *firstString = [string substringToIndex:1];
if([temp2 containsObject:firstString] == NO || temp2.count == 0)
{
if(temp2.count != 0)
{
[temp addObject:temp2];
[temp2 release];
temp2 = [[NSMutableArray alloc] init];
}
[temp2 addObject:firstString];
}
[temp2 addObject:dict];
[dict release];
}
[temp addObject:temp2];
detailListArray = [[NSArray alloc] initWithArray:temp];
[temp release];
[temp2 release];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)tableView:(UITableView *)tableView
sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
int i = 0;
for(NSArray *array in detailListArray)
{
NSString *string = [array objectAtIndex:0];
if([string compare:title] == NSOrderedSame)
break;
i++;
}
return i;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return detailListArray.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSArray *array = [detailListArray objectAtIndex:section];
return [array objectAtIndex:0];
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
NSMutableArray *titleArray = [NSMutableArray array];
[titleArray addObject:#"A"];
[titleArray addObject:#"B"];
[titleArray addObject:#"C"];
[titleArray addObject:#"D"];
[titleArray addObject:#"E"];
[titleArray addObject:#"F"];
[titleArray addObject:#"G"];
[titleArray addObject:#"H"];
[titleArray addObject:#"I"];
[titleArray addObject:#"J"];
[titleArray addObject:#"K"];
[titleArray addObject:#"L"];
[titleArray addObject:#"M"];
[titleArray addObject:#"N"];
[titleArray addObject:#"O"];
[titleArray addObject:#"P"];
[titleArray addObject:#"Q"];
[titleArray addObject:#"R"];
[titleArray addObject:#"S"];
[titleArray addObject:#"T"];
[titleArray addObject:#"U"];
[titleArray addObject:#"V"];
[titleArray addObject:#"W"];
[titleArray addObject:#"X"];
[titleArray addObject:#"Y"];
[titleArray addObject:#"Z"];
return titleArray;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSArray *array = [detailListArray objectAtIndex:section];
return (array.count - 1);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"CELL"] autorelease];
NSArray *array = [detailListArray objectAtIndex:indexPath.section];
NSDictionary *dict = [array objectAtIndex:indexPath.row + 1];
cell.textLabel.text = [dict objectForKey:#"Name"];
return cell;
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *array = [detailListArray objectAtIndex:indexPath.section];
NSDictionary *dict = [array objectAtIndex:indexPath.row + 1];
int entryID = [[dict objectForKey:#"ID"] intValue];
// Do what ever you want to do with the selected row here....
}
This is the code that I have used in one of the recent projects.
I was working on one project where I need dynamic solutions for same problem so I figure out this solutions which returns dictionary with only available sections. Hope it help someone.
-(NSMutableDictionary *)getSortedDataWithArray:(NSArray *)dataArray{
NSMutableDictionary *allDataDictionary = [[NSMutableDictionary alloc]init];
for(int i = 0 ; i< dataArray.count ;i++){
NSString *currentStr = [[[dataArray objectAtIndex:i] substringToIndex:1] uppercaseString];
NSArray *allKeysArray = allDataDictionary.allKeys;
if([allKeysArray containsObject:currentStr]){
NSMutableArray *currentArray = [[NSMutableArray alloc] initWithArray:[allDataDictionary valueForKey:currentStr]];
[currentArray addObject:[dataArray objectAtIndex:i]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF beginswith[c] %#" ,currentStr];
NSArray *finalArray = [currentArray filteredArrayUsingPredicate:predicate];
[allDataDictionary setValue:finalArray forKey:currentStr];
}
else{
NSMutableArray *finalArray = [[NSMutableArray alloc] initWithObjects:[dataArray objectAtIndex:i], nil];
[allDataDictionary setValue:finalArray forKey:currentStr];
}
}
return allDataDictionary;
}

Array not getting populated with new data

In my app I am using an array to get some data inside the method but every time after adding the object to the array, I check its contents then always it shows me 0 objects inside the array and also after that I am reloading the table view but nothing is happening.no event are called. I am showing my code here:
in .h file
#interface ModalView:UIViewController
<UITableViewDelegate,UITableViewDataSource,UIScrollViewDelegate>
{
NSMutableArray *imageName;
}
#property (nonatomic,retain)NSMutableArray *imageName;
in .m file:-
#synthesize imageName;
- (void)viewDidLoad {
[super viewDidLoad];
imageName=[[NSMutableArray alloc] init];
[tableView1 reloadData];
tableView1.delegate=self;
tableView1.dataSource=self;
}
-(void)searchImagesInCategory:(NSString *)string
{
string1=string;
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory= [paths objectAtIndex:0];
NSString *path=[documentsDirectory stringByAppendingPathComponent:#"1.sqlite"];
//Open the database
//might have to make database as property
if(sqlite3_open([path UTF8String], &dataBase) ==SQLITE_OK)
{
sqlite3_stmt *statement;
NSString *strSQL = [[NSString alloc]init];
strSQL = #"select ImageName from tblLanguageElement where Category='";
strSQL = [[strSQL stringByAppendingString:string1] stringByAppendingString:#"'"];
const char *bar = [strSQL UTF8String];
if(sqlite3_prepare(dataBase, bar, -1, &statement, NULL) == SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSLog(#"%#",[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]);
NSString *string2=[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
// [imageName addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)]];
NSLog(string2);
[imageName addObject:string2];
[imageName retain];
}
//tableView1.delegate=self;
//tableView1.dataSource=self;
[self.tableView1 reloadData];
}
}
//return 1;
//[tableView1 reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView1 cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView1 dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.imageView.image= [UIImage imageNamed:[imageName objectAtIndex:indexPath.row]];
return cell;
}
This is my code. Why my array (imageName) is not getting the data inside the method and why table view is not reloading?
I know you're instantiating your array in viewDidLoad, but what happens if you add it at the beginning of the method -(void)searchImagesInCategory:(NSString *)string:
imageName = [[NSMutableArray alloc] init];
Since you declared the object in your header file as nonatomic retain, then synthesized and allocated it in your implementation, you do not need to retain it each time you add something to it. You should try removing the [imageName retain];