Add / Delete Item from NSMutableDictionary through UITableView - objective-c

I've got a .plist file with NSMutableDictionary that I am populating a UITableView like so:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *myFile = [[NSBundle mainBundle]
pathForResource:#"courses" ofType:#"plist"];
courses = [[NSMutableDictionary alloc] initWithContentsOfFile:myFile];
courseKeys = [courses allKeys];
}
And:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Course";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
NSString *currentCourseName = [courseKeys objectAtIndex:[indexPath row]];
[[cell textLabel] setText:currentCourseName];
return cell;
}
I am trying to allow the user to swipe + delete and also "add" new items to the plist using the UiTableView cells. This is the code I'm using to do this:
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
When I run the simulator and do this it gives me an error, stating
"Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (7) must be equal to the number of rows contained in that section before the update (7), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'"
Can anyone help me out here?

You are populating your table from the courseKeys Array. So in your delegate method
- (void)tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
//whether it is an add or edit or delete modify your array from which you are populating the table and reload the table
}

You are removing the row from the table but not from your data source. CourseKeys needs to be a mutableArray that you remove deleted keys from.

Related

objective c - pass array of objects to table view

i need to pass array of class objects
i have class called Student , it has some properties (name , code , account_type ....);
i call method in database to get all students object
Student_array = [data_base_helper selectAllStudents];
i need to show list of student names in table view, i made anther array called names
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [Student_array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cell_identifer = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cell_identifer forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_identifer];
}
for(Student * st in student_array){
[self.names addObject:st.student_name];
}
cell.textLabel.text = [names objectAtIndex:indexPath.row ];
return cell;
}
i find some problem with delete as i delete by index idea how to pass array of objects in table view
The idea is that you don't need to use an "array of names", you can just use your Students array directly, in this way:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [Student_array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * cell_identifer = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cell_identifer forIndexPath:indexPath];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_identifer];
}
Student *student = Student_array[indexPath.row];
cell.textLabel.text = student.student_name;
return cell;
}
When you'll need to delete a student from the tableView, you can easily remove from the array and then update the tableView accordingly, something like that:
[Student_array removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
Note that in the code above I'm assuming that you want to delete the object at the given indexPath.row and that Student_array is a NSMutableArray and not a NSArray
ps: you may want to rename Student_array in students since in objective-c it's not a good practice to name objects with a capital letter, nor to use underscores. Likely I would also rename student_name in name since student is just a repetition of the type of the object.
When You Deleted a cell from table delete items for both array Student_array and self.name array corresponding the deleted cell.

Delete cell from UITableView not from Array

I learn how work with CoreData and Table view controller. I learn from a book and there is using this function for display content of TableViewControoler.
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if(debug == 1){
NSLog(#"Running %# '%#'",self.class, NSStringFromSelector(_cmd));
}
static NSString *cellIndetifier = #"Class Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIndetifier
forIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryDetailButton;
SchoolClass *class = [self.frc objectAtIndexPath:indexPath];
NSMutableString *title = [NSMutableString stringWithFormat:#"%#", class.name];
[title replaceOccurrencesOfString:#"(null)"
withString:#""
options:0
range:NSMakeRange(0, [title length])];
cell.textLabel.text = title;
return cell;
}
Now I would like delete a record(cell) from table view controller and from coreData. I don't know what is the simplest way, but I found this:
I have one button "delete" and the button has this IBA action.
-(IBAction)deleteClassAction:(id)sender{
[self.tableView setEditing:YES animated:YES];
}
When I press the button I see something like this:
http://i.stack.imgur.com/3VAyp.png
Now I need delete the selected cell. I found some code and I prepared skeleton for deleting. But I need advice in two things.
I don't know how get the ID of deleting item and how to write code for filter - viz. comment: // the code that filters the object that has been marked for deleting cell from tableView
I don't know how delete the cell from tableView. I found the solution, which is under the comment, but it has a error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (10) must be equal to the number of rows contained in that section before the update (10), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
Here is the code with comments.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
// deleting data from CoreData database
CoreDataHelper *cdh = [(AppDelegate *) [[UIApplication sharedApplication] delegate] cdh];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"User"];
NSPredicate *filter = // the code that filters the object that has been marked for deleting cell from tableView"
[request setPredicate:filter];
NSArray *fetchedObjects = [cdh.context executeFetchRequest:request error:nil];
for(SchoolClass *class in fetchedObjects){
[_coreDataHelper.context deleteObject:class];
}
// deleting cell from tableView
if (editingStyle == UITableViewCellEditingStyleDelete) {
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
[self.tableView reloadData];
}
You just need to delete the object from your NSFetchedResultsController. You might also then want to save the NSManagedObjectContext. The fetched results controller will then update the table view assuming you've implemented the delegate methods as described in the docs.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
// deleting cell from fetched results contoller
if (editingStyle == UITableViewCellEditingStyleDelete) {
SchoolClass *class = [self.frc objectAtIndexPath:indexPath];
[[class managedObjectContext] deleteObject:class];
}
}

How to populate multiple table view sections from the same .plist

Sorry if this has been discussed already, I couldn't find what I was after..
I have a .plist file which has 2 arrays in it, which are split exactly how I would like my sections split in my table view.
I have no problem getting an array into a table view, but I cant get my head around how to tell the app that I want one array in the first section and the second array in the second section.
My code at the moment to get an array into a table is this (and it works fine):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Create string with reference to the prototype cell created in storyboard
static NSString *CellIdentifier = #"PlayerNameCell";
//Create table view cell using the correct cell type
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//Create a dictionary containing the player names
NSDictionary *players = (NSDictionary*) [[self Squad] objectAtIndex:[indexPath row]];
//Set the cell text to the player name
[[cell textLabel] setText:(NSString*)[players valueForKey:#"PlayerFullName"]];
//Set the cell detail text to the squad number
[[cell detailTextLabel] setText:(NSString*)[players valueForKey:#"PlayerSquadNumber"]];
return cell;
}
But now I have another table view where I'll need 2 sections, each reading from different arrays.
Any help would be greatly appreciated.
Many thanks
Just do the following:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
{
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"PlayerNameCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if( cell == nil ){
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
if( indexPath.section == 0 ){
NSDictionary *players = (NSDictionary*) [self.array1 objectAtIndex:indexPath.row];
cell.textLabel.text = (NSString*)[players valueForKey:#"PlayerFullName"];
cell.detailTextLabel.text = (NSString*)[players valueForKey:#"PlayerSquadNumber"];
} else {
NSDictionary *players = (NSDictionary*) [self.array2 objectAtIndex:indexPath.row];
cell.textLabel.text = (NSString*)[players valueForKey:#"PlayerFullName"];
cell.detailTextLabel.text = (NSString*)[players valueForKey:#"PlayerSquadNumber"];
}
return cell;
}
Set the number of sections to 2. For each section get the different values with [self.array2 objectAtIndex:indexPath.row].
I don't know how you are saving the plist into 2 arrays, but if you need help with that let me know.
Okay, so you have 2 arrays at the top level, and each of those arrays contains arrays, right?
You've got a couple methods you need to adjust. Return the number of top level arrays for the number of sections in the table view. In cellForRowAtIndexPath:, return the correct object for the correct section/row. Something like
[[sectionsArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row]

Display certain numbers of row at one time, click Button, display more

i m quite stucking with this problem. i have a NSArray *list holding 70 elements from a plist file. now i need to populate them to UITableView.
what i want is to display 20 items at a time, then click the 21st cell to display another 20.. then press the 41st cell to display another 20 items... and so on till all 72 cells reveal..
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
return 20;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
static NSString *addCellID = #"addMoreCell";
UITableViewCell *addCell = [tableView dequeueReusableCellWithIdentifier:addCellID];
if (indexPath.row == 0) {
static NSString *CellIdentifier = #"labelCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
return cell;
} else if (indexPath.row < 25){
NSDictionary *dic = [self.list objectAtIndex:indexPath.row];
cell.textLabel.text = [dic objectForKey:#"Title"];
cell.detailTextLabel.text = [dic objectForKey:#"Tips"];
return cell;
} else {
if (cell == nil) {
addCell.textLabel.text = #"Load More...";
return cell;
}
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 20)
{
[self.tableView reloadData];
}
}
Take an array, in which you will add 20 elements from plist, and
set numberOfRowsInSection = [array count] and
check if numberOfRowsInSection < totalNumberOfRecords in plist, if it is less, then increment numberOfRowsInSection by 1.
And in cellForRowAtIndexPath
check if (indexPath.row < totalNumberOfRecords -2 && indexPath.row < numberOfRowsInSection-1)
then add "LoadMore Cell" else not.
So I do something quite similar. You have an array with 70 strings (or dictionaries) to show in the table. The 'numberOfRowsInSection:' should be using an ivar which is initially set to 20.
When your button gets pressed, you increase the ivar by 20 (but to no more than the actual amount of data!), you reload the table, then you can scroll the table up to the "new" cell using tableView methods.

How can i reset the total rows of my table on the same button click at each time?

i am using UITableView with the following delegates.
tableView.delegate = self;
tableView.dataSource=self;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 5;enter code here
}
it will set the number of Rows in a section at the loading time.
it will trigger the following delegate and i can do whatever i need with table cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
if(indexPath.row == 0)
{
However i need to create/reset the table rows dynamically(on a button click) and need to trigger
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
this delegate to set some datas to table cell.
how can i call this delegate in a button click.and also i need to reset the total rows of my table on the same button click at each time.
can any one help me to do it.
[self.tableView reloadData];
And they all lived happily ever after.
You need to change the dataSource of your table view and then call:
[tableView reloadData];
so in a button action you should:
-(void)buttonClicked{
tableViewArray = ...//load array with new data;
[self.tableView reloadData];
}
Have to set:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
**return [tableViewArray count];**
}
- (void)buttonClicked
{
tableViewArray = ... //load array with new data;
[self.tableView reloadData];
}