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)
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:
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NSMutableArray Not showing actual values when NSLog in iphone application
I have NSMutableArray initialised as follows:
- (id)init
{
self = [super init];
if (self)
{
mySpotsArray = [[NSMutableArray alloc]init];
}
return self;
}
The array stores data of NSTable as follows:
//-----------------------------------------
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [mySpotsArray count];
[self saveMySpots];
}
//-----------------------------------------
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
Spot *sp = [mySpotsArray objectAtIndex:row];
NSString *identifier = [tableColumn identifier];
return [sp valueForKey:identifier];
[self saveMySpots];
}
//-----------------------------------------
- (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
Spot *sp = [mySpotsArray objectAtIndex:row];
NSString *identifier = [tableColumn identifier];
[sp setValue:object forKey:identifier];
[self saveMySpots];
}
I am adding and deleting objects like this:
//-----------------------------------------
- (IBAction)addSpot:(id)sender
{
[mySpotsArray addObject:[[Spot alloc]init]];
[mySpotsTable reloadData];
[self saveMySpots];
}
//-----------------------------------------
- (IBAction)deleteSpot:(id)sender
{
NSInteger row = [mySpotsTable selectedRow];
[mySpotsTable abortEditing];
if (row !=-1)
{
[mySpotsArray removeObjectAtIndex: row];
}
[mySpotsTable reloadData];
[self saveMySpots];
}
I am saving and loading array content like this:
//-----------------------------------------
- (void) saveMySpots
{
savedSpots = [NSUserDefaults standardUserDefaults];
encodedMySpotsArrayObject = [NSKeyedArchiver archivedDataWithRootObject: mySpotsArray];
[savedSpots setObject: encodedMySpotsArrayObject forKey:[NSString stringWithFormat:#"MySpotsArrayKey"]];
}
//-----------------------------------------
- (void) loadMySpots
{
savedSpots = [NSUserDefaults standardUserDefaults];
decodedMySpotsArrayObject = [savedSpots objectForKey: [NSString stringWithFormat:#"MySpotsArrayKey"]];
mySpotsArray = [NSKeyedUnarchiver unarchiveObjectWithData: decodedMySpotsArrayObject];
}
Objects are encoded and decoded like this:
//-----------------------------------------
- (id)init
{
self = [super init];
if (self)
{
_mySpot = #"My Spot";
_localOffset = 0;
}
return self;
}
//-----------------------------------------
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject: self.mySpot forKey:#"MySpotKey"];
[encoder encodeInt: self.localOffset forKey:#"LocalOffsetKey"];
}
//-----------------------------------------
- (id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if( self != nil )
{
self.mySpot = [decoder decodeObjectForKey:#"MySpotKey"];
self.localOffset = [decoder decodeIntForKey:#"LocalOffsetKey"];
}
return self;
}
Everything is properly defined in their respective .h like this
NSMutableArray *mySpotsArray;
NSUserDefaults *savedSpots;
NSData *encodedMySpotsArrayObject;
NSData *decodedMySpotsArrayObject;
All works perfect on UI level, i.e. the table is properly displayed, added, deleted, saved and loaded. But when I am trying to NSLog like this:
NSLog(#"%#", mySpotsArray);
I get this:
2012-09-19 13:41:25.372 Spot[1541:303] (
"<Spot: 0x100674ab0>",
"<Spot: 0x100674c20>",
"<Spot: 0x100675040>"
)
I've also tried this:
NSString *strData = [[NSString alloc]initWithData: decodedMySpotsArrayObject encoding:NSUTF8StringEncoding];
NSLog(#"strData: %#", strData);
and I get this:
2012-09-19 13:41:25.371 Spot[1541:303] strData: (null)
I simply need to access NSMutableArray content and then convert it to strings. The actual content what I see on UI is a table with 2 columns and 3 rows:
Yerevan 2
London -1
Los Angeles -9
What am I doing wrong?
Thanks
I think this is the expected behavior.
How does the debugger know what it should print to the console? If you want it to print something else, e.g. some property on the Spot object, you need to provide Spot with a description method.
For example:
#import <Foundation/Foundation.h>
#interface Foo:NSObject {
NSString *_bar;
}
#property (nonatomic, copy) NSString *bar;
#end
#implementation Foo
#synthesize bar = _bar;
- (NSString *)description {
return self.bar;
}
#end
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
NSMutableArray *objs = [[NSMutableArray alloc] init];
Foo *myFoo = [Foo new];
myFoo.bar = #"Mine";
Foo *yourFoo = [Foo new];
yourFoo.bar = #"Yours";
[objs addObject:myFoo];
[objs addObject:yourFoo];
NSLog(#"Objs = %#",objs);
[p release];
}
prints this to the console:
2012-09-19 06:57:10.375 Untitled 2[59494:707] Objs = (
Mine,
Yours
)
But without the description method, this is what prints to the console:
2012-09-19 07:01:12.542 Untitled 2[59853:707] Objs = (
"<Foo: 0x7f9773c080c0>",
"<Foo: 0x7f9773c0a9b0>"
)
Add this method in your Spot class
- (NSString *)description
{
NSString *str = [[NSString alloc] initWithFormat:#"%# \n %# \n%#",Var1,Var2,var3];
return str;
}
replace Var1, Var2 and Var3 with your original variable name.
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.)