I just started learning Xcode, read the book and now trying to implement what I read. The app needs to store certain data in arrays and dictionary, then table view extracts the data by automatically counting number of sections, number of rows and populating table cells with content, assigned to a key word.
Please, see my code, because I've been trying to run the app, but it gives me SIGABRT error. I don't know if new Xcode doesn't declare or call things this way(my book is for iOS3). I tried to find solutions from blogs, youtube, but the app is still not running at this point.
I know that I declared everything correctly in AppDelegate files, etc, because I used someone's sample code of one 1 array. And the table view got populated.
Help me, because something is wrong with my code with NSMutableDictionary and indexPath. Thank you!
#import "TableViewController.h"
#implementation TableViewController
#synthesize tableData;
#synthesize tableSections;
#pragma mark - View lifecycle
- (void)viewDidLoad
{ [self createData];
[super viewDidLoad];
}
-(void)createData{
NSMutableArray *category1;
NSMutableArray *category2;
category1=[[NSMutableArray alloc] init];
category2=[[NSMutableArray alloc] init];
tableSections=[[NSMutableArray alloc] initWithObjects:#"Category 1", #"Category 2", nil];
tableData=[[NSMutableArray alloc] initWithObjects:category1, category2, nil];
[category1 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleA", #"name",#"A",#"property", nil]];
[category1 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleB", #"name",#"B",#"property", nil]];
[category2 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleC", #"name",#"C",#"property", nil]];
[category2 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleD", #"name",#"D",#"property", nil]];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [tableSections count];
//return [self.tableSections count]; Also tried to use with self. Don’t know which one is correct
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self.tableSections 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];
}
cell.textLabel.text = [[[tableData objectAtIndex:indexPath.section] objectAtIndex:indexPath.row] objectForKey:#"name"];
/* Also tried this:
tableData *cellObj = [[self.tableData objectAtIndex:indexPath.section]objectAtIndex:indexPath.row];
cell.textLabel.text = cellObj.name;
/* Also tried this:
tableData *cellObj= [[[self.tableData objectAtIndex:indexPath.section]objectAtIndex:indexPath.row]objectForKey:#"name"];
cell.textLabel.text=smsObj.name; */
/* Also tried this:
NSDictionary *item = (NSDictionary *)[self.tableData objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"name"];*/
/* Also tried this way:
NSDictionary *dictionary = [tableData objectAtIndex:indexPath.section];
NSArray *array = [dictionary objectForKey:#"name"];
NSString *cellValue = [array objectAtIndex:indexPath.row];
cell.text = cellValue;
And the same way, but switched order of NSArray and NSDictionary*/
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// This I will add later, after I make my Table View Controller work
}
#end
I know I'm doing something very silly with the codes, but I'm trying to understand the right way to write the codes...
[category1 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleA", #"name",#"A",#"property", nil]];
[category1 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleB", #"name",#"B",#"property", nil]];
[category2 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleC", #"name",#"C",#"property", nil]];
[category2 addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"TitleD", #"name",#"D",#"property", nil]];
}
add this code after initilization of those arrays and try
Related
Hi I have three NSMutableArray. e.g Array - a ,b c. Let say all 3 array have a size of 3.
Would like to ask how do I go about creating 3 section each section contain 3 row (according to no. of array). In each section, the 1st row from a, 2nd row from b, 3rd row from c
1st Section:
[a objectAtIndex:1]
[b objectAtIndex:1]
[c objectAtIndex:1]
2nd Section:
[a objectAtIndex:2]
[b objectAtIndex:2]
[c objectAtIndex:2]
3rd Section:
[a objectAtIndex:3]
[b objectAtIndex:3]
[c objectAtIndex:3]
Thanks!!
create another array and push a,b,c arrays into it
NSArray container =#[a,b,c];
in your tableview cellforRow
use container[indexPath.row][indexPath.section]
You could put all the arrays (a,b,c) to another array which would act as a container. Select elements for from that container like this: container[rowIndex][sectionIndex]. Please also keep in mind setting numbers for each section:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
//should return number of arrays in container
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
//this should return number of elements corresponding to each section
Those methods are a part of UITableViewDataSource Protocol
Try this code
In .h file
#import <UIKit/UIKit.h>
#interface ArrayViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
NSMutableArray *ivContentsList;
}
// Properties
#property (nonatomic, retain) NSMutableArray *contentsList;
.m file
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *firstSection = [NSArray arrayWithObjects:#"one", #"two", nil];
NSArray *secondSection = [NSArray arrayWithObjects:#"three", #"four", #"five", nil];
NSArray *thirdSection = [NSArray arrayWithObject:#"six"];
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:firstSection, secondSection, thirdSection, nil];
[self setContentsList:array];
[array release], array = nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger sections = [[self contentsList] count];
return sections;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
NSArray *sectionContents = [[self contentsList] objectAtIndex:section];
NSInteger rows = [sectionContents count];
return rows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *sectionContents = [[self contentsList] objectAtIndex:[indexPath section]];
NSString *contentForThisRow = [sectionContents objectAtIndex:[indexPath row]];
static NSString *CellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[[cell textLabel] setText:contentForThisRow];
return cell;
}
You can try a NSmutableDictionary like:
NSMutableDictionary *myDict = [[NSMutableDictionary alloc] init];
[myDict setObject:Array1 forKey:#"Section1"];
[myDict setObject:Array2 forKey:#"Section2"];
[myDict setObject:Array3 forKey:#"Section3"];
NSLog(#"Result %#",myDict);
Now you can use this dictionary to configure cell.
I've made a UITableView in my ViewController. In this table view I want to add my data from NSMutableArray, but it does not seem to add the data. Any ideas?
This is the code I'm using.
- (void)viewDidLoad
{
scoreArray = [[NSMutableArray alloc] init];
NSDictionary *myVehicle = [[NSDictionary alloc] initWithObjectsAndKeys:#"Escape", #"name", #"SUV", #"type", nil];
[scoreArray addObject:myVehicle];
[super viewDidLoad];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = [[scoreArray objectAtIndex:indexPath.row] objectForKey:#"name"];
cell.detailTextLabel.text = [[scoreArray objectAtIndex:indexPath.row] objectForKey:#"type"];
return cell;
}
Based on your code you should be able to see one row. But here with no details, the problem is quite difficult to be identified.
Anyway, verify the following:
Does the datasource (and delegate) is set? This is done via XIB or by code?
Did you implement - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section correctly?
Sample
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [scoreArray count];
}
The method - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView should be implemented if you need a number of sections greater than 1. By default returns one.
In addition, I would modify a little bit the viewDidLoad method like the following.
- (void)viewDidLoad
{
[super viewDidLoad]; // call it before any further initialization
scoreArray = [[NSMutableArray alloc] init];
NSDictionary *myVehicle = [[NSDictionary alloc] initWithObjectsAndKeys:#"Escape", #"name", #"SUV", #"type", nil];
[scoreArray addObject:myVehicle];
}
Make sure your .h file indicates that this is the delegate for the UITableView:
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
Also make sure you implement the required datasource methods. In addition to what you have, you must have these:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [scoreArray count];
}
I have this arquivo.plist below.
I looked at Apple's documentation, but I could not find how to make the listing look and I hope someone can help me.
In the first UITableView, I make a list of names present in arquivo.plist using the following code and loading the following method below.
What I'm trying to do is: When the user clicks on a tableView name, he is taken to a second screen with a new tableView that will display the "frams" of that user.
The problem is that the code I'm using to select the "frams" is the same code that I am using for listing the names on the first screen, but it is not working, because each user has only one name, but it has several "frams".
When I try to implement this, I can even assemble the array with the "frams" and pass using segue (i'll show the array with an NSLog), but this array can not be displayed as a tableView for an error that Xcode is giving me:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary length]:
unrecognized selector sent to instance 0x8b87a60'
The code from the fist view (ViewController.m) is below the contatos.plist
I hope you understand what I'm trying to do and bring me a light!
Thank you all!
a screenshot of the .plist file is bellow:
http://img268.imageshack.us/img268/7356/jl26.png
For reference and for you to better understand the issue, when the user clicks on a table name, an array is generated with "frams" this patient (patients have on average 3 frams each). The Array NSLog that it should be passed to the other page and comport a new table generates the following text:
12/12/2013 16:10:13.513 rer [24251:70 b] (
{
1 = 11;
2 = 12;
3 = 13;
}
I think that's where the problem lies, because this method of Array can not be implemented in a TableView, so I look a light of a better way to mount this array and select frams when I click a patient
So here is my ViewController.m:
#import "ViewController.h"
#import "Contato.h"
#import "perfilViewController.h"
#interface ViewController ()
-(void) loadContacts;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self loadContacts];
}
-(void) loadContacts
{
NSString *plistCaminho = [[NSBundle mainBundle] pathForResource:#"contatos"
ofType:#"plist"];
NSDictionary *pl = [NSDictionary dictionaryWithContentsOfFile:plistCaminho];
NSArray *dados = [pl valueForKey:#"contatos"];
contatos = [[NSMutableArray alloc] init];
for (NSDictionary *item in dados) {
NSString *nome = [item valueForKey:#"nome"];
NSString *telefone = [item valueForKey:#"telefone"];
NSString *fram = [item valueForKey:#"fram"];
Contato *c = [[Contato alloc] initWithNome:nome andTelefone:telefone andFram:fram];
[contatos addObject:c];
}
}
#pragma mark UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return contatos.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CelulaContatoCacheID = #"CelulaContatoCacheID";
UITableViewCell *cell = [self.tabelaContatos dequeueReusableCellWithIdentifier:CelulaContatoCacheID];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CelulaContatoCacheID];
}
Contato *contato = [contatos objectAtIndex:indexPath.row];
cell.textLabel.text = contato.nome;
return cell;
}
#pragma mark -
#pragma mark UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Contato *contato = [contatos objectAtIndex:indexPath.row];
NSString *msg = [NSString stringWithFormat:#"Fram:%#",contato.fram];
fran = [[NSMutableArray alloc] init];
fran = [NSMutableArray arrayWithObject:contato.telefone];
NSLog(#"finalmente eu consegui essa porra!!!%#", fran);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Contato"
message:msg
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[self.tabelaContatos deselectRowAtIndexPath:indexPath animated:YES];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"vai"]) {
NSIndexPath *indexPath = [self.tabelaContatos indexPathForSelectedRow];
perfilViewController *destViewController = segue.destinationViewController;
Contato *contato = [contatos objectAtIndex:indexPath.row];
fran = [[NSMutableArray alloc] init];
fran = [NSMutableArray arrayWithObject:contato.fram];
destViewController.frans = fran;
NSLog(#"%#%#", fran, destViewController.frans);
}
}
#end
I'd firstly do:
//declare NSDictionary *pl; in the ViewController.h
pl = [NSDictionary dictionaryWithContentsOfFile:plistCaminho];
Then to display Names, i'd simply use the dictionary as such:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[pl objectForKey:#"contatos"] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
//following commented line not needed anymore
//Contato *contato = [contatos objectAtIndex:indexPath.row];
cell.textLabel.text = [[[pl objectForKey:#"contatos"]
objectAtIndex:indexPath.row]
objectForKey:#"nome"];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//following commented line not needed anymore
//Contato *contato = [contatos objectAtIndex:indexPath.row];
//NOTE: fran is a dictionary now
//change "fran" declaration in the ViewController.h to
//NSDictionary *fran;
fran = [[NSDictionary alloc] init];
fran = [[pl objectForKey:#"contatos"]
objectAtIndex:indexPath.row];
NSLog(#"finalmente eu consegui essa porra!!!%#", fran);
//...
//don't deselectRow (the indexPathForSelectedRow will not work correctly later)
//[self.tabelaContatos deselectRowAtIndexPath:indexPath animated:YES];
}
then on -prepareForSegue i'd pass the dictionary associated with the selected row:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"vai"]) {
NSIndexPath *indexPath = [self.tabelaContatos indexPathForSelectedRow];
perfilViewController *destViewController = segue.destinationViewController;
//following commented line not needed anymore
//Contato *contato = [contatos objectAtIndex:indexPath.row];
//NOTE: fran is a dictionary now
//change "fran" declaration in the ViewController.h to
//NSDictionary *fran;
fran = [[NSDictionary alloc] init];
fran = [[[pl objectForKey:#"contatos"]
objectAtIndex:indexPath.row]
objectForKey:#"fram"];
//NOTE: destViewController.frans should be a dictionary
//handle it appropriately
destViewController.frans = fran;
}
}
so basically, all dictionary use, no need for Contato *contato at all.
EDIT: As for your current method, you would be better off replicating the same structure.
As in:
[array of names] has {dictionary with user details} having a key that has {dictionary of frams}
I'd recommend you not using a dictionary to store your Fram values, use an array instead.
This way, you can get the Fram values like this:
for (NSDictionary *item in dados) {
NSString *nome = [item valueForKey:#"nome"];
NSString *telefone = [item valueForKey:#"telefone"];
NSArray *fram = [item valueForKey:#"fram"];
Contato *c = [[Contato alloc] initWithNome:nome andTelefone:telefone andFram:[fram objectAtIndex:index]];
[contatos addObject:c];
}
Where index is an integer variable you'll have to work out how to handle.
PS: be a little more polite when logging you app ;)
Developing a iPAD app, where I'm trying to populate table, This is how i'm doing:
In view did load, I'm creating two dictionary object and adding object as Pdf and Excel.
- (void)viewDidLoad
{
[super viewDidLoad];
arrDocuments = [[NSMutableArray alloc] init];
NSArray *arr1 = [NSArray arrayWithObjects:#"PDF", nil];
NSDictionary *pdf = [NSDictionary dictionaryWithObjects:arr1 forKeys:nil];
NSArray *arr2 = [NSArray arrayWithObjects:#"Excel", nil];
NSDictionary *excel = [NSDictionary dictionaryWithObjects:arr2 forKeys:nil];
[arrDocuments addObject:pdf];
[arrDocuments addObject:excel];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [arrDocuments count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
//return [arrReceipes count];
NSDictionary *dictionary = [arrDocuments objectAtIndex:section];
NSArray *array = [dictionary objectForKey:[self.sortedKeys objectAtIndex:section]];
return [array count];
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableView *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell ==nil) {
cell = [[UITableViewCell alloc]initWithFrame:CGRectZero reuseIdentifier:MyIdentifier];
}
return cell;
}
With this implementation I'm not able to see table view.Its going to main method and showing me SIGABRT message.Where I'm going wrong??
While creating NSDictionary, you have passed nil in place of keys array,
NSDictionary *pdf = [NSDictionary dictionaryWithObjects:arr1 forKeys:nil];
You should give proper objects and keys to the dictionary. This method expects objects and keys to be given in an array as you can see in its method signature.
+ (instancetype)dictionaryWithObjects:(NSArray *)objects forKeys:(NSArray *)keys
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;