How to form an array of dictionaries for multilevel(any number) tableview from the core data object - objective-c

I need to create array of dictionaries, of data coming from a database object. This array of dictionaries can be of multiple level,and has a parent child relationship depending upon the level.
From the array form I need to create a multilevel table view (level can be any depending upon the data loaded)
Depending upon the catal_id of the coredata object, next set of Catal objects are loaded from the database. Code supporting is shown as below.
I want to create the array as shown in the image
From the above load of loadMainCatalData I am able to load the table but on didSelectRowAtIndexPath I am not able to form the proper array for the expand collapse table. Catal object gets added twice, on viewDidLoad.
There is some issue with function.
**Please help to form the proper array to load the table. Stuck here **.
The coredata object is of the below format:
<__NSArrayM 0x109c3b7a0>(
<Catal: 0x104cccfb0>
(entity: Catal; id: 0xd000000008880006 <x-coredata://F849E220-C905-4359-8CD5-18D5E35FC13A/Catal/p546> ; data: {
breadcrumb = "";
"catal_id" = "SNV2";
"id_ni" = 1;
"id_parent" = 0;
imgId = 1;
title = "Adventure";
"nb_element" = 1010;
order = 38;
}),
<Catal: 0x104ccd3f0> (entity: Catal; id: 0xd000000006e40006 <x-coredata://F849E220-C905-4359-8CD5-18D5E35FC13A/Catal/p441> ; data: {
breadcrumb = "";
"catal_id" = "SNV1";
"id_ni" = 1;
"id_parent" = 0;
imgId = 38;
title = Gros;
"nb_element" = 1366;
order = 82;
}),
<Catal: 0x104ccd6e0> (entity: Catal; id: 0xd00000000a500006 <x-coredata://F849E220-C905-4359-8CD5-18D5E35FC13A/Catal/p660> ; data: <fault>),
<Catal: 0x104ccd790> (entity: Catal; id: 0xd000000005d40006 <x-coredata://F849E220-C905-4359-8CD5-18D5E35FC13A/Catal/p373> ; data: <fault>),
<Catal: 0x104ccd940> (entity: Catal; id: 0xd00000000acc0006 <x-coredata://F849E220-C905-4359-8CD5-18D5E35FC13A/Catal/p691> ; data: <fault>)
)
My code goes as below
- (void)viewDidLoad {
[super viewDidLoad];
if (!self.catalList || self.catalList.count == 0) {
[self loadDataCatal];
isAlreadyInserted = NO;
}
}
- (void)loadDataCatal{
[self loadMainCatalData];
self.arForTable = [NSMutableArray array];
[self.arForTable addObjectsFromArray:self.arrayOriginal];
}
-(void)loadMainCatalData {
NSMutableArray *arrCatalList = [[NSMutableArray alloc] init];
if (catLevel == NULL){
[arrCatalList addObjectsFromArray:[Catal fillDataCatal:#"0" :#"0"]];
}
self.arrayOriginal = [NSMutableArray array];
for (Catal *objCatal in arrCatalList){
ProductCategoryFilter *objProductCatFilter = [[ProductCategoryFilter alloc] init];
[objProductCatFilter setCatalCategory:objCatal];
NSMutableArray *arr = [self loadSubCatalData:objCatal];
[objProductCatFilter setArrCatalSubCategory:arr];
[self.arrayOriginal addObject:objProductCatFilter];
}
}
-(NSMutableArray *)loadSubCatalData:(Catal *)objCatal{
NSMutableArray *arrSubCatal = [NSMutableArray array];
ProductCategoryFilter *objProductCatFilter = [[ProductCategoryFilter alloc] init];
[objProductCatFilter setCatalCategory:objCatal];
NSArray *arrCatal = [Catal fillDataCatal:objCatal.catal_id :#""];
NSMutableArray *arrSubCat = [NSMutableArray array];
for (Catal *subCatal in arrCatal){
ProductCategoryFilter *objSubCatFilter = [[ProductCategoryFilter alloc] init];
[objSubCatFilter setCatalCategory:subCatal];
NSMutableArray *arr = [self loadSubCatalData:subCatal];
[objSubCatFilter setArrCatalSubCategory:arr];
[arrSubCat addObject:objSubCatFilter];
}
[objProductCatFilter setArrCatalSubCategory:arrSubCat];
[arrSubCatal addObject:objProductCatFilter];
return arrSubCatal;
}
// the ProductCategoryFilter class
#import <Foundation/Foundation.h>
#import "Catal+CoreDataClass.h"
#interface ProductCategoryFilter : NSObject
#property (nonatomic,strong) Catal* catalCategory;
#property (nonatomic,strong) NSMutableArray * arrCatalSubCategory;
#end
// Catal CoreDataObject
#import <Foundation/Foundation.h>
#import "Catal+CoreDataClass.h"
+(BOOL)fillSubDataCatal:(NSString *)catal_id
{
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context = [[CoreDataHelper getInstance] managedObjectContext];
NSError *error;
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Catal" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate;
predicate = [NSPredicate predicateWithFormat:#"id_parent == %#", catal_id];
[fetchRequest setPredicate:predicate];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
DebugLog(#"[fetchedObjects count] : %lu",(unsigned long)fetchedObjects.count);
if([fetchedObjects count] > 0)
{
return true;
}
return false;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier =#"AMG_PP_SubCategoryTableCell";
AMG_PP_SubCategoryTableCell *cell = (AMG_PP_SubCategoryTableCell *) [self.tblProductCategory dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil];
cell =(AMG_PP_SubCategoryTableCell *)[nib objectAtIndex:0];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
ProductCategoryFilter *objCat = [self.arForTable objectAtIndex:indexPath.row];
[cell.imgRadio setImage:[UIImage imageNamed:#"PlusIcon"]];
cell.textLabel.text = objCat.catalCategory.libelle; //] [ valueForKey:#"name"];
// [cell setIndentationLevel:[[[self.arForTable objectAtIndex:indexPath.row] valueForKey:#"level"] intValue]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
AMG_PP_SubCategoryTableCell *cell = (AMG_PP_SubCategoryTableCell *)[self.tblProductCategory cellForRowAtIndexPath:indexPath];
[self.tblProductCategory deselectRowAtIndexPath:indexPath animated:YES];
ProductCategoryFilter *objCatal = [self.arForTable objectAtIndex:indexPath.row];
if([[objCatal arrCatalSubCategory] count] > 0) {
NSMutableArray *ar=[objCatal arrCatalSubCategory];
if(ar != nil){
isAlreadyInserted=NO;
for(ProductCategoryFilter *dInner in ar ){
NSInteger index=[self.arForTable indexOfObjectIdenticalTo:dInner];
isAlreadyInserted=(index>0 && index!=NSIntegerMax);
if(isAlreadyInserted) break;
}
if(isAlreadyInserted) {
[self miniMizeThisRows:ar];
} else {
NSUInteger count=indexPath.row+1;
NSMutableArray *arCells=[NSMutableArray array];
for(ProductCategoryFilter *dInner in ar ){
[arCells addObject:[NSIndexPath indexPathForRow:count inSection:0]];
[self.arForTable insertObject:dInner atIndex:count++];
}
[cell.imgRadio setImage:[UIImage imageNamed:#"MinusIcon"]];
[tableView insertRowsAtIndexPaths:arCells withRowAnimation:UITableViewRowAnimationLeft];
}
}
}
}
-(void)miniMizeThisRows:(NSArray*)ar{
for(ProductCategoryFilter *dInner in ar ){
NSUInteger indexToRemove=[self.arForTable indexOfObjectIdenticalTo:dInner];
NSMutableArray *arInner=[dInner arrCatalSubCategory];
if(arInner && [arInner count]>0){
if (arInner != nil) {
[self miniMizeThisRows:arInner];
}
}
if([self.arForTable indexOfObjectIdenticalTo:dInner]!=NSNotFound) {
[self.arForTable removeObjectIdenticalTo:dInner];
[self.tblProductCategory deleteRowsAtIndexPaths:[NSArray arrayWithObject:
[NSIndexPath indexPathForRow:indexToRemove inSection:0]
]
withRowAnimation:UITableViewRowAnimationRight];
}
}
}

Here's the simple code which help you in understanding the how to create a array of dictionary :
var arrayOfDict = [[String : String]]()
let dict1 = ["FirstName" : "Abc" , "LastName" : "XYZ"]
let dict2 = ["HouseNo" : "WW49", "Locality" : "GymKhana"]
let dict3 = ["City" : "mnb", "State" : "lkop" , "Country" : "mkl"]
arrayOfDict.append(dict1)
arrayOfDict.append(dict2)
arrayOfDict.append(dict3)
print(arrayOfDict)

Related

Objective-c: Use predicate with an object

I have a search bar for my table view and until now I used a predicate to check if the data array contains the search bar value. But now there are objects in my data array and now I don't know how to use the predicate. Here is my code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [cd] %#", self.controller.searchBar.text];
NSMutableArray *temp = [[NSMutableArray alloc] init];
for (int i = 0; i < [self.data count]; i++) {
Student *student = [[Student alloc] initWithIdentifier:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"id"] name:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"name"] is_public:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"is_public"] password:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"passwort"]];
[temp addObject:student];
}
self.results = [temp filteredArrayUsingPredicate:predicate];
Now it compares the search bar value with the object. But it should compare the search bar value with object.name. How can I do this?
EDIT:
The Student code:
#implementation Student
- (id)initWithIdentifier:(NSString *)identifier name:(NSString *)name is_public:(NSString *)is_public password:(NSString *)password {
self= [super init];
if( self ) {
self.identifier = identifier;
self.name = name;
self.is_public = is_public;
self.password = password;
}
return self;
}
- (NSDictionary*)writableRepresentation {
NSMutableDictionary *writableRepresentation= [NSMutableDictionary dictionaryWithCapacity:4];
[writableRepresentation setValue:self.identifier forKey:#"Identifier"];
[writableRepresentation setValue:self.name forKey:#"Name"];
[writableRepresentation setValue:self.is_public forKey:#"is_public"];
[writableRepresentation setValue:self.password forKey:#"password"];
return writableRepresentation;
}
+ (Student*)studentFromDictionary:(NSDictionary*)dictionaryRepresentation {
return [[Tipprunde alloc] initWithIdentifier:[dictionaryRepresentation valueForKey:#"Identifier"] name:[dictionaryRepresentation valueForKey:#"Name"] is_public:[dictionaryRepresentation valueForKey:#"is_public"] password:[dictionaryRepresentation valueForKey:#"password"]];
}
#end
It don't seem to work with SELF.name. I get the following error:
-[Student objectForKey:]: unrecognized selector sent to instance...

NSMutableArray- removeObject results with removing object and a nil element

Firstly, I am new with Objective C.
I have my class Song that has a pair of attributes.
In my main class i got a variable allSongs that is a NSMutableArray and in this array have I added all my song-objects.
My problem comes when trying to call [self.allSongs removeObject:OBJECT];
Using the debugger, I can see that before the call, the list looks as expected. But after the call it will result that the targeted object will be removed but also the first element in the array will turn to nil.
Is this a common pointer problem or what?
Here is my code:
in h file
#property (nonatomic, strong) NSMutableArray *songs;
#property (nonatomic, strong) NSMutableArray *allChapters;
in m file
- (void)viewDidLoad
{
self.chosenChapter = [[NSString alloc]initWithFormat:self.chosenChapter];
self.allChapters = [[NSMutableArray alloc]init];
//Chapter names and chapter page range
chapters = [[NSArray alloc]initWithObjects:#"chapter1", #"chapter2", #"chapter3", nil];
chaptersRange = [[NSArray alloc]initWithObjects:#"25", #"51", #"88", nil];
//Filnames of every song
files = [[NSMutableArray alloc] initWithObjects:#"test", #"Feta_fransyskor", nil];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey: #"page" ascending: YES];
self.songs = [[NSMutableArray alloc]init];
for(int i = 0; i < chapters.count; i++){
Song *chapter = [[Song alloc]init];
[chapter setPage:(NSString *)self.chaptersRange[i]];
[chapter setTitle:(NSString *)self.chapters[i]];
[self.allChapters addObject:chapter];
[self.songs addObject:chapter];
}
NSString *filePath;
int i;
for (i = 0; i < files.count; i++) {
filePath = [[NSBundle mainBundle] pathForResource:files[i] ofType:#"txt"];
if(filePath){
NSError *error;
NSString *textFromfile = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error: &error];
/*
index
0 for page number
1 for title name
2 for melody name
3 -> for lyrics
*/
NSMutableArray *newLineseparatedText = (NSMutableArray *)[textFromfile componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
if(newLineseparatedText){
Song *newSong = [[Song alloc]init];
[newSong setPage:newLineseparatedText[0]];
[newSong setTitle:newLineseparatedText[1]];
[newSong setMelody:newLineseparatedText[2]];
[newLineseparatedText removeObjectAtIndex:0]; //remove page number
[newLineseparatedText removeObjectAtIndex:0]; //remove title name
[newLineseparatedText removeObjectAtIndex:0]; //remove melody name
[newSong setLyric:[newLineseparatedText componentsJoinedByString:#"\n"]];
[songs addObject:newSong];
}
}
}
[self.songs sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[super viewDidLoad];
}
-(void)addChapters{
for(int i = 0; i < self.allChapters.count; i++){
if([self.songs containsObject:self.allChapters[i]] == false)
[self.songs addObject:self.allChapters[i]];
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey: #"page" ascending: YES];
[self.songs sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
}
-(void)addChapters{
for(int i = 0; i < self.allChapters.count; i++){
if([self.songs containsObject:self.allChapters[i]] == false)
[self.songs addObject:self.allChapters[i]];
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey: #"page" ascending: YES];
[self.songs sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
}
-(void)removeChaptersExcept:(Song *) chapter{
for(int i = 0; i < self.allChapters.count; i++){
if(self.allChapters[i] != chapter && [self.songs containsObject:self.allChapters[i]])
[self.songs removeObject:self.allChapters[i]];
}
}
last line of this code is were i get an error, as the mutableArray has a couple of nil elements.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([self.chosenChapter isEqualToString:#"Alla"]){
[self addChapters];
}
else{
Song *chapter = nil;
for(int i = 0; i < self.allChapters.count; i++){
if([((Song *)self.allChapters[i]).title isEqualToString:self.chosenChapter]){
chapter = self.allChapters[i];
break;
}
}
[self addChapters];
[self removeChaptersExcept:chapter];
}
NSString *cellIdentifier = nil;
UITableViewCell *cell = nil;
NSString *page = ((Song *)self.songs[indexPath.row]).page;
and here are some screen bumps
This is before removing first object
This is after the first object was removed. You see how one element disapeared as expected and the other is set too nil?
Sometimes the Variables View shows incorrect values.
An array can't contain nil values, so this is definitely a case where the values are wrong.
You state that your application crashes on this line:
NSString *page = ((Song *)self.songs[indexPath.row]).page;
My guess is that self.songs[indexPath.row] simply doesn't have a property called page.
Try to replace this line with this code:
Song *s = self.songs[indexPath.row];
if (s == nil)
{
NSLog("Song is nil! How can that be?");
}
else
{
NSLog("Page is %#", s.page);
}
It will help you pin-point the problem. Good luck.

Error: index 1 beyond bounds [0 .. 0]

I am a rookie in Xcode and I have been using the UITableViewController which shows this error.
This is the error message:
* Terminating app due to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM objectAtIndex:]: index 1 beyond bounds [0 .. 0]'
* First throw call stack:
(0x1c91012 0x10cee7e 0x1c330b4 0x36d0 0xc58d5 0xc5b3d 0xacce83 0x1c50376 0x1c4fe06 0x1c37a82 0x1c36f44 0x1c36e1b 0x1beb7e3 0x1beb668 0x1665c 0x2132 0x2065)
libc++abi.dylib: terminate called throwing an exception
(lldb)
This is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.row == 0) {
NSString *strURL = [NSString stringWithFormat:#"http://localhost:8888/GetDetail.php?choice=row0"];
NSArray *arrayImagesNames = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:strURL]];
arrayDataFromServer2 = [[NSMutableArray alloc]init];
NSEnumerator *enumForNames = [arrayImagesNames objectEnumerator];
id objName;
while ( objName = [enumForNames nextObject]) {
[arrayDataFromServer2 addObject:[NSDictionary dictionaryWithObjectsAndKeys:objName, #"name", nil]];
}
NSString *nn = [[arrayDataFromServer2 objectAtIndex:indexPath.row] objectForKey:#"name"];
row1 = [nn intValue];
NSLog(#"%d", row1);
CompanyProfileViewController *profile = [self.storyboard instantiateViewControllerWithIdentifier:#"Profile"];
[self.navigationController pushViewController:profile animated:YES];
profile.profileid = row1;
NSLog(#"%d", profile.profileid);
}
if (indexPath.row == 1) {
NSString *strURL = [NSString stringWithFormat:#"http://localhost:8888/GetDetail.php?choice=row1"];
NSArray *arrayImagesNames = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:strURL]];
arrayDataFromServer2 = [[NSMutableArray alloc]init];
NSEnumerator *enumForNames = [arrayImagesNames objectEnumerator];
id objName;
while (objName = [enumForNames nextObject]) {
[arrayDataFromServer2 addObject:[NSDictionary dictionaryWithObjectsAndKeys:objName, #"name", nil]];
}
NSString *nn = [[arrayDataFromServer2 objectAtIndex:indexPath.row] objectForKey:#"name"];
row1 = [nn intValue];
NSLog(#"%d", row1);
CompanyProfileViewController *profile = [self.storyboard instantiateViewControllerWithIdentifier:#"Profile"];
[self.navigationController pushViewController:profile animated:YES];
profile.profileid = row1;
NSLog(#"%d", profile.profileid);
}
if (indexPath.row == 2) {
NSString *strURL = [NSString stringWithFormat:#"http://localhost:8888/GetDetail.php?choice=row2"];
NSArray *arrayImagesNames = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:strURL]];
arrayDataFromServer2 = [[NSMutableArray alloc]init];
NSEnumerator *enumForNames = [arrayImagesNames objectEnumerator];
id objName;
while ( objName = [enumForNames nextObject]) {
[arrayDataFromServer2 addObject:[NSDictionary dictionaryWithObjectsAndKeys:objName, #"name", nil]];
}
NSString *nn = [[arrayDataFromServer2 objectAtIndex:indexPath.row] objectForKey:#"name"];
row1 = [nn intValue];
NSLog(#"%d", row1);
CompanyProfileViewController *profile = [self.storyboard instantiateViewControllerWithIdentifier:#"Profile"];
[self.navigationController pushViewController:profile animated:YES];
profile.profileid = row1;
NSLog(#"%d", profile.profileid);
}
if (indexPath.row == 3) {
NSString *strURL = [NSString stringWithFormat:#"http://localhost:8888/GetDetail.php?choice=row3"];
NSArray *arrayImagesNames = [[NSMutableArray alloc] initWithContentsOfURL:[NSURL URLWithString:strURL]];
arrayDataFromServer2 = [[NSMutableArray alloc]init];
NSEnumerator *enumForNames = [arrayImagesNames objectEnumerator];
id objName;
while ( objName = [enumForNames nextObject]) {
[arrayDataFromServer2 addObject:[NSDictionary dictionaryWithObjectsAndKeys:objName, #"name", nil]];
}
NSString *nn = [[arrayDataFromServer2 objectAtIndex:indexPath.row] objectForKey:#"name"];
row1 = [nn intValue];
NSLog(#"%d", row1);
CompanyProfileViewController *profile = [self.storyboard instantiateViewControllerWithIdentifier:#"Profile"];
[self.navigationController pushViewController:profile animated:YES];
profile.profileid = row1;
NSLog(#"%d", profile.profileid);
}
}
When I click on the second cell (index.row == 1) this error would occur.
I have used breakpoint and the error was on the line:
"NSString *nn = [[arrayDataFromServer2 objectAtIndex:indexPath.row] objectForKey:#"name"];"
Please Help!
Swift 4
after more time i am get the love for this Error 😄
when you use the tableView from the storyboard and implementing in your code :
hint that and compare :
between the number of section and numberOfRowsInSection == storyboard and code
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 3
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
You have an array and you have either 0 or 1 elements in it. Now you are trying to extract 2nd element from it, [0] is first, and [1] is second.
EDIT:
As you are not sure when the array will contain 1 or more objects. Therefore you can use as:
NSString *nn=nil;
if([arrayDataFromServer2 count]>1){
nn = [[arrayDataFromServer2 objectAtIndex:indexPath.row] objectForKey:#"name"];
}

Xcode find table view section row on detail text label

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.)

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;
}