I load data from plist to uitableview like this:
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"data.plist"];
NSMutableDictionary *resultDic = [[NSMutableDictionary alloc] init];
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSDictionary *myDict = [NSDictionary dictionaryWithContentsOfFile:path];
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"purpleKey"])
{
NSArray *purple = [myDict objectForKey:#"Purple"];
[resultArray addObject:#"Purple"];
[resultDic setValue:purple forKey:#"Purple"];
}
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"orangeKey"])
{
NSArray *orange = [myDict objectForKey:#"Orange"];
[resultArray addObject:#"Orange"];
[resultDic setValue:orange forKey:#"Orange"];
}
self.tableData = resultDic;
self.sectionsTitle = resultArray;
}
titleForHeaderInSection
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [sectionsTitle objectAtIndex:section];
}
my plist structure
My question is:
How can I manually set title for Purple header and Orange header without to changing names in plist file?
like this: Purple = Category 1, Orange = Category 2
EDIT
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sectionsTitle.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [sectionsTitle objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int num = [[tableData objectForKey:[sectionsTitle objectAtIndex:section]] count];
if (num > 3) {
num = 3;
}
return num;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *dict = [[tableData objectForKey:[sectionsTitle objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.numberOfLines = 1;
cell.textLabel.font = [UIFont systemFontOfSize:11];
cell.textLabel.text = [NSString stringWithFormat:#"%# - %#", [dict objectForKey:#"Name"], [dict objectForKey:#"Address"]];
if ([dict objectForKey:#"Address"] == (NULL)) {
//do nothing
}
return cell;
}
From the look of your code, the section headers are coming from resultsArray, which you are populating with the constant strings Orange and Purple.
You can just put different constant strings into that array, unless I'm missing something.
So, instead of
[resultArray addObject:#"Orange"];
Use
[resultArray addObject:#"Category 1"];
Related
I have a very simple app to learn how to work with sections in UITableView but there is an exception -
2013-09-17 08:46:19.956 Sections[4497:c07] * -[__NSArrayI
objectAtIndex:]: message sent to deallocated instance 0x9566d40
The whole methods are below - need help.
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *path = [[NSBundle mainBundle] pathForResource:#"sortednames" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
self.names = dict;
NSArray *array = [[_names allKeys] sortedArrayUsingSelector:#selector(compare:)];
_keys = array;
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
NSLog(#"%lu", (unsigned long)[_keys count]);
return [_keys count];
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *key = [_keys objectAtIndex:section];
NSArray *nameSection = [_names objectForKey:key];
return [nameSection count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [_keys objectAtIndex:section];
NSArray *nameSection = [_names objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier];
}
cell.textLabel.text = [nameSection objectAtIndex:row];
return cell;
}
- (NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *key = [_keys objectAtIndex:section];
return key;
}
You must retain _keys array like that:
_keys = [[[_names allKeys] sortedArrayUsingSelector:#selector(compare:)] retain];
Here you are first taking values in other array and then passing it to _keys..thats not proper way of doing it..
just directly pass the values to _keys like below
_keys = [[_names allKeys] sortedArrayUsingSelector:#selector(compare:)];
also check for self.names, you are doing the same thing there.
Hope this will help you.
I need to filter data in UITableview by text entered in UISearchbar. I followed this example but there data in NSMutableArray and I can't alter it under my requirements. My data is NSMutableDictionary. I'm stuck on this for long time.
My data:
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *path = [[documentPaths lastObject] stringByAppendingPathComponent:#"data.plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path];
NSMutableDictionary *resultDic = [[NSMutableDictionary alloc] init];
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSDictionary *myDict = [NSDictionary dictionaryWithContentsOfFile:path];
sectionKeys = [NSMutableArray new];
sectionsTitle = [NSMutableArray new];
NSArray *tableArray = [myDict objectForKey:#"Black"];
[resultArray addObject:#"Black"];
[resultDic setValue:tableArray forKey:#"Black"];
[sectionsTitle addObject:[NSString stringWithFormat:#"%#", [tableData valueForKey:#"Black"]]];
[sectionCord addObject:[NSString stringWithFormat:#"%#", [tableData valueForKey:#"Coordinates"]]];
[sectionKeys addObject:#"Section1"];
self.tableData = resultDic;
self.sectionsTitle = resultArray;
[myTable reloadData];
My table:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return sectionKeys.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [sectionKeys objectAtIndex:section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
int rowCount;
if(self.isFiltered)
rowCount = [[filteredTableData objectForKey:[sectionsTitle objectAtIndex:section]] count];
else
rowCount = [[tableData objectForKey:[sectionsTitle objectAtIndex:section]] 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:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
if(isFiltered){
NSDictionary *dict = [[filteredTableData objectForKey:[sectionsTitle objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#", [dict objectForKey:#"Name"]];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", [dict objectForKey:#"Address"]];
}
else{
NSDictionary *dict = [[tableData objectForKey:[sectionsTitle objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
cell.textLabel.text = [NSString stringWithFormat:#"%#", [dict objectForKey:#"Name"]];
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", [dict objectForKey:#"Address"]];
}
return cell;
}
My search:
#pragma mark - SearchBar Delegate -
-(void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)text{
if(text.length == 0)
{
isFiltered = FALSE;
NSLog(#"false");
}
else
{
isFiltered = true;
NSLog(#"true");
filteredTableData = [[NSMutableDictionary alloc] init];
for (MyAnnotation* ann in tableData)
{
NSRange nameRange = [ann.title rangeOfString:text options:NSCaseInsensitiveSearch];
NSRange descriptionRange = [ann.description rangeOfString:text options:NSCaseInsensitiveSearch];
if(nameRange.location != NSNotFound || descriptionRange.location != NSNotFound)
{
[filteredTableData addObject:ann];
//error
}
}
}
[myTable reloadData];
}
First of all, you need to create a state/flag for the controller/data source, in order for it to know weather you are in search/filter mode.
Then, if you are in search mode, point the data source methods to the filteredArray.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
int numberOfSections = 0;
if (_searchMode)
{
numberOfSections = self.filteredDataDict.allKeys.count;
}
else
{
numberOfSections = self.tableData.allKeys.count;
}
return numberOfSections;
}
Hope it's understood.
I'm making a note taking app for the iPad, and it lets the user draw lines, and right now, it can save the pages of the notebook by saving each page as a PNG in the documents directory. Here's the code I have to save the images:
- (IBAction)saveImage:(id)sender {
UIImage *saveImage = drawImage.image;
if (saveImage != nil)
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat: #"%#-%d.png", #"image", numberOfPages] ];
NSData* data = UIImagePNGRepresentation(saveImage);
[data writeToFile:path atomically:YES];
}
}
Just as a side note, numberOfPages is an int that is set to add 1 each time a "new page" button is pressed, this way, each image is named "image1", "image2", etc.
So my question is: How would I set up a UITable so the user can see a list of all the pages they've made.
Thanks so much for your time,
Karl
Each time you make a new page, add a string with the image's name to an array. Then, iterate through the array to populate a UITableView. When the user selects a cell, open the file with that name.
#import "RootViewController.h"
#implementation RootViewController
#synthesize keys, names;
AppDelegate *appD;
- (void)viewDidLoad
{
[super viewDidLoad];
appD = (AppDelegate *)[[UIApplication sharedApplication] delegate];
names = appD.data;
NSArray *array = [[names allKeys] sortedArrayUsingSelector:#selector(compare:)];
keys = array;
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return [keys count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = indexPath.section;
NSUInteger row = indexPath.row;
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [appD.data objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SectionsTableIdentifier];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = [nameSection objectAtIndex:row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *key = [keys objectAtIndex:section];
key = [key substringFromIndex:2];
return key;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = indexPath.section;
NSUInteger row = indexPath.row;
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [appD.data objectForKey:key];
appD.theInfo.primary = [nameSection objectAtIndex:row];
[self performSegueWithIdentifier:#"secondarySegue" sender:self];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
This is for a table in a navigation controller that populates itself from a .plist and moves to another table when a cell is clicked. The tableview is connected to the view controller with delegate and datasource outlets.
I am trying to learn how to code a UITableView and is having some problems with the programming of the section.
I have declared 3 arrays with strings and 1 array with the 3 arrays.
firstSection = [NSArray arrayWithObjects:#"Red", #"Blue", nil];
secondSection = [NSArray arrayWithObjects:#"Orange", #"Green", #"Purple", nil];
thirdSection = [NSArray arrayWithObject:#"Yellow"];
array = [[NSMutableArray alloc] initWithObjects:firstSection, secondSection, thirdSection, nil];
To shows the headers
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
NSString * title;
title = [NSString stringWithFormat:#"%#" , [array objectAtIndex:section]];
return title;
}
which shows the array itself as the headers
therefore is it possible to actually show the name of the sections using the names of the arrays such as firstSection and secondSection?
In your case, it's better to store your arrays in an NSDictionary. For example, if you declare and synthesize an NSDictionary variable called tableContents and an NSArray called titleOfSections, you can do something like this:
- (void)viewDidLoad {
[super viewDidLoad];
//These will automatically be released. You won't be needing them anymore (You'll be accessing your data through the NSDictionary variable)
NSArray *firstSection = [NSArray arrayWithObjects:#"Red", #"Blue", nil];
NSArray *secondSection = [NSArray arrayWithObjects:#"Orange", #"Green", #"Purple", nil];
NSArray *thirdSection = [NSArray arrayWithObject:#"Yellow"];
//These are the names that will appear in the section header
self.titleOfSections = [NSArray arrayWithObjects:#"Name of your first section",#"Name of your second section",#"Name of your third section", nil];
NSDictionary *temporaryDictionary = [[NSDictionary alloc]initWithObjectsAndKeys:firstSection,#"0",secondSection,#"1",thirdSection,#"2",nil];
self.tableContents = temporaryDictionary;
[temporaryDictionary release];
}
Then in the table view controller methods:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [self.titleOfSections count];
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
return [[self.tableContents objectForKey:[NSString stringWithFormat:#"%d",section]] count];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
//Setting the name of your section
return [self.titleOfSections objectAtIndex:section];
}
Then to access the contents of each array in your cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
NSArray *arrayForCurrentSection = [self.tableContents objectForKey:[NSString stringWithFormat:#"%d",indexPath.section]];
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
cell.textLabel.text = [arrayForCurrentSection objectAtIndex:indexPath.row];
return cell;
}
can u do like this
NSArray *SectionArray = [[NSArray alloc]initwithArray:[array objectAtIndex:section]];
NSString * title;
title = [NSString stringWithFormat:#"%#" , [SectionArray objectAtIndex:section]];
return title;
I have a plist with an alphabetical indexed list of entries. I now want to add a further level so that each entry has a definition text (like a small dictionary.) I need some advice as to how to modify my plist and code to accommodate this. The existing code is below - it's from the Apress book, but I can't seem to modify it for another level.
NSString *path = [[NSBundle mainBundle] pathForResource:#"sortedglossary" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc]initWithContentsOfFile:path];
self.names = dict;
[dict release];
NSArray *array = [[names allKeys] sortedArrayUsingSelector:#selector(compare:)];
self.keys = array;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"numberOfSectionInTable start");
return [keys count];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"numberOfRowsInSection start");
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
return [nameSection count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
NSString *key = [keys objectAtIndex:section];
NSArray *nameSection = [names objectForKey:key];
static NSString *SectionsTableIdentifier = #"SectionsTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SectionsTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SectionsTableIdentifier] autorelease];
}
cell.text = [nameSection objectAtIndex:row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSLog(#"titleForHeader");
NSString *key = [keys objectAtIndex:section];
return key;
}
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return keys;
}
There are a number of ways to accomplish this. Normally I will just create another child of the root node in the plist for definitions.
So your plist would have the array of your entries and it would have another dictionary. The dictionary contains the definition text, keyed by the values from the first array. That way, you can just look up the definition when you need it.
So the structure would look roughly like this:
Root
Entries(NSArray)
0 => entryA(NSString)
1 => entryB(NSString)
...
x => entryX(NSString)
Definitions(NSDictionary)
entryA(NSString) => definitionA(NSString)
entryB(NSString) => definitionB(NSString)
...
entryX(NSString) => definitionX(NSString)