how to take UITable view visible paths and more rows - iphone

Now I am taking index paths of visible tableview cells.But I want to take 3 more index path from visible rows,How can I do that ?
NSArray *visiblePaths = [tblView indexPathsForVisibleRows];

Assuming just one section, you can just create them, minding the max rows for that section:
NSMutableArray *visiblePaths = [tblView indexPathsForVisibleRows] mutableCopy];
NSInteger lastIndexPath = [visiblePaths lastObject];
NSInteger lastRow = lastIndexPath.row;
NSInteger extraRows = 3;
NSInteger maxRow = MIN(lastRow+extraRows, [self tableView:tblView numberOfRowsInSection:0] - 1);
for (int i = lastRow+1; i < maxRow; i++) {
NSIndexPath *newPath = [NSIndexPath indexPathForRow:i inSection:0];
[visiblePaths addObject:newPath];
}
It's doable for more sections (and/or for rows before the first visible) also. Hopefully it's clear how one would extend this to cover those requirements.

Related

How to add multiple NSIndexPath into NSMutableArray

I am trying to add nsindexpath into an array .. i am able to add only one indexpath .if i try to add another indexpath into array ..the debugger shows only the newest indexpath .
for (int i = 0 ; i<[notificationArray count]; i++)
{
selectedSymptIndexPath = [NSIndexPath indexPathForRow:selectedSymptomIndex inSection:keyIndexNumber];
selectedSympIPArray = [[NSMutableArray alloc]init];
[selectedSympIPArray addObject:selectedSymptIndexPath];
}
even if i try to put [selectedSympIPArray addObject:selectedSymptIndexPath]; outside for loop still its adding only the newest indexpath rather than showing multiple indexpaths
You are alloc init'ing the array every time in the loop, dont do that.
Try this:
selectedSympIPArray = [[NSMutableArray alloc]init];
for (int i = 0 ; i<[notificationArray count]; i++)
{
selectedSymptIndexPath = [NSIndexPath indexPathForRow:selectedSymptomIndex inSection:keyIndexNumber];
[selectedSympIPArray addObject:selectedSymptIndexPath];
}
In your code , you alloc every time in iteration. It's totally wrong. Find your mistake.
You can use this code....
selectedSympIPArray = [NSMutableArray array];
for (int i = 0 ; i<[notificationArray count]; i++)
{
selectedSymptIndexPath = [NSIndexPath indexPathForRow:selectedSymptomIndex inSection:keyIndexNumber];
[selectedSympIPArray addObject:selectedSymptIndexPath];
}

Tableview update 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows?

Yes there are so many question ask on stack overflow on similar title of question. I read those all but i never see my problem equivalent to them.
Now my problem is if when i update table section 0 having 3 rows on click of headerview on section 0 and then again i click on same header for delete all 3 rows from the section 0, this work fine with me. But if i open(update section 0 with 3 rows) and then i click on another header section (another section i want to open then after 0th section) my application crashed. I mean i want to if i click other section then my other section should have open and previous open section should have to close. see my code for insertion and deletion sections and rows,
-(void)sectionHeaderView:(TableHeaderView*)sectionHeaderView sectionOpened:(NSInteger)section{
self.sectionOpen = YES;
//Create an array containing data of rows and section which to be inserted in tableView.
NSMutableArray *dataInsertArray = [NSMutableArray arrayWithArray:[self.tableDataSourceDictionary objectForKey: [self.sortedKeys objectAtIndex:section]]];
NSInteger countOfRowsToInsert = [dataInsertArray count];
NSMutableArray *indexPathsToInsert = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < countOfRowsToInsert; i++) {
[indexPathsToInsert addObject:[NSIndexPath indexPathForRow:i inSection:section]];
}
[self.tableContents setObject:dataInsertArray forKey:[self.sortedKeys objectAtIndex:section]];
//Create an array containing data of rows and section which to be delete from tableView.
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
NSInteger previousOpenSectionIndex = self.openSectionIndex;
if (previousOpenSectionIndex != NSNotFound ) {
self.sectionOpen = NO;
[previousTableHeader toggleOpenWithUserAction:NO];
NSInteger countOfRowsToDelete = [[self.tableContents objectForKey: [self.sortedKeys objectAtIndex:section]] count];
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
}
[self.tableContents removeObjectForKey:[self.sortedKeys objectAtIndex:previousOpenSectionIndex]];
}
// Apply the updates.
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:indexPathsToInsert withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
self.openSectionIndex = section;
self.previousTableHeader = sectionHeaderView;
}
And my data-source methods,
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
NSInteger numberOfSection = [self.sortedKeys count];
return numberOfSection;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSArray *listData =[self.tableContents objectForKey: [self.sortedKeys objectAtIndex:section]];
NSInteger numberOfRows = [listData count];
return numberOfRows;
}
My crash report,
Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:1070
2013-02-18 11:44:49.343 ManageId[1029:c07] 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 (0) must be equal to the number of rows contained in that section before the update (3), 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).'
Simply Suppose my 2 sections has contain 3 - 3 rows then it will worked file But if 2 sections contain 3 - 2 rows then it crash. I want to toggle two sections click on updating header of section with inconsistent numbers of rows in those sections.
Than
I found that please replace that code in your code with that code. you have to delete data with old one index not with current one....
the commented line was yours please check that...
if (previousOpenSectionIndex != NSNotFound){
 self.sectionOpen = NO;
[previousTableHeader toggleOpenWithUserAction:NO];
//NSInteger countOfRowsToDelete = [[self.tableContents objectForKey: [self.sortedKeys objectAtIndex:section]] count];
NSInteger countOfRowsToDelete = [[self.tableContents objectForKey: [self.sortedKeys objectAtIndex:previousOpenSectionIndex]] count];   
for (NSInteger i = 0; i < countOfRowsToDelete; i++) {
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:previousOpenSectionIndex]];
 }
[[self.tableContents objectForKey: [self.sortedKeys objectAtIndex:previousOpenSectionIndex]] removeAllObjects];
}

Populating UITableView cells

Ok so I have wrote some code in this function:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"tableviwcell is getting called");
properties = [NSUserDefaults standardUserDefaults];
NSDictionary *events_dict = [properties objectForKey:#"events_dict"];
NSDictionary *events = [events_dict objectForKey:#"event"];
am_participants = [events objectForKey:#"amParticipants"];
pm_participants = [events objectForKey:#"pmParticipants"];
UITableViewCell *cell = nil;
cell = [tableView dequeueReusableCellWithIdentifier:#"currentCell"];
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"currentCell"];
}
int sizeofam = [am_participants count];
int sizeofpm = [pm_participants count];
NSMutableArray *participants =[[NSMutableArray alloc] init];
NSLog(#"size of am: %i", sizeofam);
if(sizeofam > 0 && sizeofpm > 0){
for(int i = 0; i < sizeofam; i++){
NSDictionary *ampart_dict = [am_participants objectAtIndex:i];
NSString *ampart_email = [ampart_dict objectForKey:#"email"];
NSString *ampart_email_extra = [#"am" stringByAppendingString:ampart_email];
[participants addObject:ampart_dict];
}
for(int i = 0; i < sizeofpm; i++){
NSDictionary *pmpart_dict = [pm_participants objectAtIndex:i];
NSString *pmpart_email = [pmpart_dict objectForKey:#"email"];
NSString *pmpart_email_extra = [#"pm" stringByAppendingString:pmpart_email];
[participants addObject:pmpart_dict];
NSLog(#"%#", participants);
}
int sizeofparticipants = [participants count];
for(int i = 0; i < sizeofparticipants; i++){
NSString *participanti = [[participants objectAtIndex:i] objectForKey:#"email"];
for(int j = 0; j < sizeofparticipants; j++){
NSString *participantj = [[participants objectAtIndex:j] objectForKey:#"email"];
if([participanti isEqualToString:participantj]){
NSLog(#"Participant j: %#", participantj);
[participants removeObjectAtIndex:j];
sizeofparticipants = [participants count];
}
}
}
Basically I need to merge together the two arrays am_participants and pm_participants in to one array of participants. Each object in the array is a dictionary full of various values such as name, email etc. I then have to remove any duplicate values from the list (for example if someone is in the am list and pm list. I am doing that by removing values if their email address is the same in either list.
After this I need to display the new array of participants called 'participants' in one list by populating the cells with the list of participants.
I have set the number of cells to 30.
However The cells get populated with different names randomly when scrolling down the list as thought the array positions are being moved around aswell as duplicate values appearing.
Can someone explain what I am doing wrong?
Thanks!
the cell assignment code is not mentioned above but i assume that you are assigning values from participants as your cell's content as explained. The problem is you are creating your array inside cellForRowAtIndexPath:. This method gets called every time a new cell is to be displayed, thus, you are recreating your participants for every row. You need to move the code you have above to viewDidLoad or viewDidAppear.

Adding cell.textLabel.text value to an array and displaying it

i have a UItableView and i have two buttons on each cell. You can add or subtract 1 from the cell's textLabel. I add the cells current value +1 with this:
- (IBAction)addLabelText:(id)sender{
num = [NSString stringWithFormat:#"%d",[cell.textLabel.text intValue] +1];//<--- num is an NSNumber
number = [[NSMutableArray alloc]initWithObjects:num, nil];//<---- number is an NSMutableArray
[myTableView reloadData];
}
and I am trying to subtract the text and store it in an array with this:
- (IBAction)subtractLabelText:(id)sender
{
if ( [[cell.textLabel text] intValue] == 0){
num = [NSString stringWithFormat:#"%d",[num intValue] +0];
[number addObject:num];
[myTableView reloadData];
}
else{
num = [NSString stringWithFormat:#"%d",[num intValue] -1];
[number addObject:num];
[myTableView reloadData];
}
}
and im trying to set the cell.textLabel.text in the cellForRow like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
cell.textLabel.text = [number objectAtIndex:indexPath.row];//<---IM USING THIS LINE TO SET THE NEW TEXTLABEL
cell.textLabel.text = #"1";
return cell;
}
MY PROBLEM
So, the addition works, but the subtraction does not. It doesnt work at all when i press the button on the cell. Thanks in advance!!
At the risk of pointing out the obvious... you seem to have hard-coded the text property to #"1".
cell.textLabel.text = [number objectAtIndex:indexPath.row];//<---IM USING THIS LINE TO SET THE NEW TEXTLABEL
cell.textLabel.text = #"1";
The first line is probably doing what you think... but then you're immediately changing it back to #"1".
EDIT - Based on clarification in comments, here's what I think you want to do. I will modify your own code as posted.
Note that I put my addition into viewDidLoad as an example. You could do this in init, or any number of other places, at whatever point you know how many cells you want to show.
- (void)viewDidLoad {
self.number = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [HOW MANY CELLS DO YOU WANT?]; i++) {
[self.number addObject:#"1"];
}
[myTableView reloadData];
}
- (IBAction)addLabelText:(id)sender {
// Note that I'm assuming here that your button is a direct child of the cell.
// If not, you'll need to change this.
UITableViewCell *cell = [sender superview];
NSInteger newNumber = [cell.textLabel.text intValue] + 1;
NSString *newNumberString = [NSString stringWithFormat:#"%d", newNumber];
[self.number replaceObjectAtIndex:cell.tag withObject:newNumberString];
[myTableView reloadData];
}
- (IBAction)subtractLabelText:(id)sender {
// Note that I'm assuming here that your button is a direct child of the cell.
// If not, you'll need to change this.
UITableViewCell *cell = [sender superview];
NSInteger newNumber = [cell.textLabel.text intValue] - 1;
newNumber = (newNumber < 0) ? 0 : newNumber;
NSString *newNumberString = [NSString stringWithFormat:#"%d", newNumber];
[self.number replaceObjectAtIndex:cell.tag withObject:newNumberString];
[myTableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
}
cell.tag = indexPath.row; // Important for identifying the cell easily later
cell.textLabel.text = [self.number objectAtIndex:indexPath.row];
return cell;
}
I don't want to get too much more in depth, but I would recommend you take a look at reloading only the cell modified, instead of calling [myTableView reloadData] every time.

Deleting multiple (not yet loaded) rows in UITableView

I'm having a bit of trouble trying to delete rows that haven't been loaded (or not visible) from a UITableview.
My setup is as follows -
There are two sections in the tableview and each element in section 1 is associated with multiple elements from section two.
To give you an example (The data isn't really related to what I'm trying to do, but I believe this will be an example that doesn't really require much explanation)
Section 1
BMW
Acura
Merc
Section 2
328i
335i
RX
LX
TX
C300
C550
My internal model goes something like this -
NSMutableArray Cars[]
NSMutableArray Models[]
cars[0] = "BMW"
cars[1] = "Acura"
cars[2] = "Merc"
Each element in Models[] is a vector and their conents are listed below
Models = [ ["328i", "335i"], ["RX", "LX", "TX"], ["C300", "C550"] ];
So for the functionality I'm trying to build. If the user clicks delete and tries to delete BMW, the App needs to remove the entry for BMW from section 1 and the entries for 328i and 335i in section two. However, the user is free to delete any single row of section two independently.
Can anyone point me to a way I can proceed with this?
NSMutableArray *Cars = [[NSMutableArray alloc] initWithObjects:#"BMW",#"Acura",#"Merc",nil];
NSMutableArray *Arr1 = [[NSMutableArray alloc]initWithObjects:#"328i", #"335i",nil];
NSMutableArray *Arr2 = [[NSMutableArray alloc]initWithObjects:#"RX", #"LX", #"TX",nil];
NSMutableArray *Arr3 = [[NSMutableArray alloc]initWithObjects:#"C300", #"C550",nil];
NSMutableArray * Models = [[NSMutableArray alloc] initWithObjects:Arr1,Arr2,Arr3,nil];
On delete if you delete BMW then remove 1st element from Models array and and 1st element from Cars array and reload table.
i.e.
[Cars removeObjectAtIndex:0];
[Models removeObjectAtIndex:0];
[tableview reload]; //tableview - object of UiTableView
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
int row = indexPath.row;
if(indexPath.section ==0) {
// Need to remove both the Car and the Models associated with it.
// Begin updates. Doesn't commit edits till endUpdates;
[tableView beginUpdates];
// Get the indexPaths to be removed.
// Cars is straight forward.
NSMutableArray *carsIndexPath = [[NSMutableArray alloc] init];
NSIndexPath *carsIndexPathObj = [NSIndexPath indexPathForRow:indexPath.row inSection:0];
[carsIndexPath addObject:carsIndexPathObj];
// Manually make index paths for models associated with the car.
NSMutableArray *modelIndexPaths = [self getIndexPaths:indexPath.row];
// Now remove from model
[models removeObjectAtIndex:indexPath.row];
[cars removeObjectAtIndex:indexPath.row];
// Remove from Table
[tableView deleteRowsAtIndexPaths:carsIndexPaths withRowAnimation:UITableViewRowAnimationLeft];
[tableView deleteRowsAtIndexPaths:modelIndexPaths withRowAnimation:UITableViewRowAnimationLeft];
// Commit updates
[tableView endUpdates];
// Reload data.
[tableView reloadData];
}
}
-(NSMutableArray *) getIndexPaths:(NSInteger) index {
NSMutableArray *indexPathArray = [[NSMutableArray alloc] init];
int offset = 0;
for (int i=0; i<index; i++) {
NSMutableArray *tempArr = [models objectAtIndex:i];
offset += [tempArr count];
}
NSMutableArray *currentModels = [models objectAtIndex:index];
for (int i=0; i<[currentModels count]; i++) {
NSIndexPath *indexPathTemp = [NSIndexPath indexPathForRow:offset+i inSection:1];
[indexPathArray addObject:indexPathTemp];
}
return indexPathArray;
}
(If this makes any sense at all)