OSX NSTableView insertRowAtIndexes - objective-c

i already checked Using NSTableView insertRowsAtIndexes solution but It does not solve my problem.
i want insert row in nstableview at particular index(add dynamically)
index Set is valid, still it causes Program crash
NSIndexSet *indexSet=[NSIndexSet indexSetWithIndex:i];
[myTableView insertRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationEffectFade];
1)is any thing wrong in my code?
2)Is there any another way to add row at particular index(add dynamically)?

The code is correct but first you have to insert the model object in the data source array to keep model and view in sync.

I got My mistake..... problem In other Code so This code is fine
But I want to add some points About insertRowsAtIndexes: method
Hope it will helps to other people
1)Dont called reloadData() because you are adding particular number of rows so calling reloadData() will reload all data and it will causes crash
2) Calling this method multiple times within the same beginUpdates and endUpdates block is allowed, and changes are processed incrementally
3)Most Important thing is indexSet must be within range
if you are Enter valid indexSet then The numberOfRows in the table view is automatically increased by the count of indexes.
4)you can select animation according to your need
Sample Code :
[yourTableView beginUpdates];
NSIndexSet* theIndexSet = [NSIndexSet indexSetWithIndex:[self.yourTableContents count]-1];
[yourTableView insertRowsAtIndexes:theIndexSet withAnimation:NSTableViewAnimationEffectFade];
[yourTableView endUpdates];

Related

Deleting A TableView Cell Populated By A Dictionary

So, deleting a table view cell is pretty straight forward. You remove the object from the array, and reload the table views data. Now... I have a table view that is populated from an NSMutableDictionary rather than array (we need to because we are parsing data and storing it). Does anyone know how to delete a cell via this method? I've tried simply calling [tableView reloadData]; which surprisingly worked, but obviously created an endless loop. I do not like endless loops. Does anyone have any suggestions? I couldn't find any relevant information in my research.
This is some relevant code in the cellForRowAtIndexPath delegate:
if (![frString isEqual:#"COOL STUFF"] && [subString isEqualToString:#"COOL"]) {
NSLog(#"A COOL is showing where it shouldn't, and it's %#", subString);
//remove all cells starting with COOL
[myDictionary removeObjectForKey:[self.dictName objectAtIndex:row]];
[tableView reloadData];
}
Also, I'd rather hide the cell instead of permanently removing the info from the dictionary. Is this possible?
There are a few things you're doing wrong :
You shouldn't remove the rows in the cellForRowAtIndexPath, because that's called when the tableview wants to render. So you remove a row, and then it renders again, calls cellForRowAtIndexPath:,...
Either delete the rows, or reload the data. deleteRowsAtIndexPaths: deletes sets of rows with animation, reloadData reloads the whole tableView, so it cancels the animation, and deleteRowsAtIndexPaths: becomes pointlesss
Ensure that you return the proper numberOfRowsInSection: did you remove the data from your dictionary ?

Using for loop to add to an array, objects aren't being added until for loop is completely done looping

So, I am using the code below to cycle through json arrays if the json array returns positive, I add the json array to another array containing all of total arrays. This can take some time to complete however, because it is going through several different json urls plugging in different dynamic information.
I edited the code below to show more basic information. My problem is that data isnt actually entered into the array until the for loop is finished. I need it to be added as soon as it finds it, not after it runs through all the onlineChannels.count - Any help?
for (int i = 0; i<onlineChannels.count; i++) {
[jsonResults addObject:[parsingJson objectAtIndex:0]];
NSLog(#"%i",jsonResults.count);
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
[self.tableView reloadData];
} else {
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
[self.tableView reloadData];
}
}
My problem is that data isnt actually entered into the array until the for loop is finished.
How do you know?
I see that you're calling -reloadData, so perhaps you're expecting the change to be reflected in your table immediately? I believe that your objects are being added to the array immediately, but the change isn't displayed on the table right away. -reloadData doesn't actually redraw the table -- drawing happens as part of the main run loop. You're probably running this code on the main thread, and by doing so you're preventing the run loop from getting any time to redraw the table.
The best way to solve this sort of problem is to move time consuming processes like your loop to background threads. That will leave the main thread free to redraw the table as necessary, and it'll make your app more responsive as well.
Also, making the table reload all its data every time you add a single item even when that item's row isn't being displayed seems quite wasteful. Consider instead calling a method like reloadRowsAtIndexPaths:withRowAnimation: to update only the part of the table that has changed.

How do you correctly get a row value from a table view?

I have implemented code that returns 0 every time. I'm trying to remove a string from a mutable array with the row value selected after hitting a button.
Related code:
- (IBAction)remove:(id)sender {
NSIndexPath *selectedIndexPath = [_tableView2 indexPathForSelectedRow];
[names removeObject:[NSString stringWithFormat:#"%i",selectedIndexPath.row]];
testLabel.text=[NSString stringWithFormat:#"%i",selectedIndexPath.row];
[_tableView2 reloadData];
}
The test label shows 0 every time the button is pressed, no matter where the tableview is selected.
Let me know if there is other relevant code (like the tableView) that you want me to post.
For a UITableView, the selected row concept is only valid while the user is touching the row. For that reason indexPathForSelectedRow is documented as returning “An index path identifying the row and section indexes of the selected row or nil if the index path is invalid.”
My opinion is that you are obtaining a nil result, and later calling the row method in that nil results in the zero that your are seeing as your name.
The solution depends on the rest of your data source implementation, but probably will involve storing the tapped index in didSelectRowAtIndexPath: to later use it in your remove method.
(I supposed that you are not using the allowsMultipleSelectionDuringEditing option nor are you editing the table).
Instead of:
[names removeObject:[NSString stringWithFormat:#"%i",selectedIndexPath.row]];
Try:
[name removeObjectAtIndex:selectedIndexPath.row];
Also, instead of using #"%i", try using #"%d" as mentioned here
Hope this helps!

Dynamically updating sections of UITableView without using reloadData

First off I sincerely apologize if this has been answered. I have been battling with this for too long. I would appreciate any kind of help.
I am developing an application that gets data asynchronously from different web sources and parses it into objects that are handled by my main Model. This model provides information for a UITableView. When data is received and parsed, i need to modify the number of sections and rows in the table view. I first receive the data that decides the number of sections, and then asynchronously data that modifies the number of rows in each section and their content. I have the table views data sources set up.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.sijainti.pysakit count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
//if ([[[self.sijainti.pysakit objectAtIndex:section] ajatStr] count] == 0) return 1;
NSLog(#"ajatStr of section: %d count: %d",section, [[[self.sijainti.pysakit objectAtIndex:section] ajatStr] count]);
return [[[self.sijainti.pysakit objectAtIndex:section] ajatStr] count];
}
The object names are in Finnish (long story). The second line of numberOfRowsInSection was commented to ease debugging. Now, because the data is dynamic i need to update the interface when i have data ready for display, or the user wont know about it until they scroll away and back again. I have a method for this:
- (void)updateRowWithCell:(SCPysakki *)valmisPysakki {
if (!valmisPysakki.isInArray) return;
int section = [self.sijainti.pysakit indexOfObject:valmisPysakki];
[self.tableView beginUpdates];
NSIndexSet *sectionSet = [NSIndexSet indexSetWithIndex:section];
[self.tableView reloadSections:sectionSet withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
This is called only after the number of sections is known. I do NOT want to use reloadData due to efficiency, and animation. I used to have this set up so that i had only rows and was just drawing rows inside of the rows. But once the rows became taller than the iphone screen, it became very unclear, because you couldn't see the title. So i made them sections, and the rows drawn real rows. Then i was suddenly faced with a problem. reloadRowsAtIndexPaths: withRowAnimation: worked absolutely fine but using reloadSections: withRowAnimation: gave me this exception:
* Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037
2012-09-17 04:11:27.769 pysappi[2351:f803] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
I was able to eliminate this by adding the [self.tableView endUpdate] and [self.tableView endUpdate] to the update method. But oh no, that only works if I:
Use reloadData after receiving the data deciding the number of sections (which in turn shortens the tableview so that after the whole update the user at the top of the table after every single update. I would rather update the sections dynamically, without using reloadData, except when removing Sections, but if I try to do this i get the exception again.)
update the sections after receiving data for only one Row (so if I try to update all the rows in the section once I've received all their data, I get the exception again.)
Now this creates a situation where creating a good user interface becomes impossible. I'm convinced that the underlying problem is not solved with the start and end updating calls, but that just fixes it for some very very odd reason.
I also tried adding the rows manually with insertRowsAtIndexPaths: and updating them manually also, but this returns the exact same error. During a long debugging progress i have been able to determine that this exception rises after cellForRowAtIndexPath: gets called and it returns a cell for one of the new rows that was added during the updating, even though the numberOfRowsInSection should have updated the amount of rows. I also suppose that if those few circumstances apply this is why the start and end updating methods make the row updating work.
The only thing that has worked outside of what i explained above, is using only reloadData, but that is just practically impossible considering the amount of updating.
This became a lot longer than i thought, and its 4.30 AM. Not the first time I'm up this late thanks to this exception. If you need more information ask. Thank you in advance.
(Answered in the comments. Converted to a community wiki answer. See Question with no answers, but issue solved in the comments (or extended in chat) )
#deleted_user wrote:
number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (0), - you had a section with zero rows and did an update with a row - cocoa didnt see that as an insert and failed you

reloadData calls numberOfSections, numberOfRows, not cellForRowAtIndexPath

first of all sorry if this isn't formatted correctly, first time doing this. I've been using stackoverflow to find help for a long time now and it's been very helpful (thank you all), but this is the first time I've posted a question of my own. This question has been asked many times, but when I call [myTable reloadTable] the methods numberOfSectionsInTableView and numberOfRowsInSection are called but not cellForRowAtIndexPath.
Every answer I've seen when searching has been a variation of:
1) The tableView is nil
2) numberOfRowsInSection is 0
3) tableView's delegate/data source not set
4) calling reloadTable on the wrong uiTableView.
None of these are the case for me so I'm wondering what else could be wrong.
What I'm trying to do:
I have a custom uitableviewcell with a button on it, when the button is pressed I want to change the attributes of the cell (for an example, let's just say I want to change the cell title to "Button Pressed"). I then want to pause for a moment and then delete the cell.
Not sure if this is important, but my tableView is inside a UIViewController, and the viewController is the delegate and dataSource.
I have a method (below) that fires when the button is pressed and the cell attributes are changed as necessary, however when I try to refresh the table to show the changes it doesn't work. The first time [remTable reloadData] is called, numberofsectionsintableview and numberofrowsinsection are called but not cellforrowatindexpath. However, the second time [remTable reloadData] is called all three methods are called and everything works correctly.
doneCell.remName.text=#"BUTTON PRESSED";
[remTable reloadData];
NSLog(#"sleep");
sleep(1);
[remList removeObject:doneReminder];
[remTable reloadData];
To test this I put nslog statements at the beginning of numberofsections, numberofrows and cellforrow, the output is the name of the method followed by the number (for numberofsections/numberofrows).
Output:
numberofsections 1
numberofrows 3
sleep
numberofsections 1
numberofrows 2
cellforrow
Any ideas as to why cellforrow's not being called the first time? Thanks in advance, please let me know if there's anything else I can add to clarify.
A table view doesn't actually request its cells until it needs to display them. When you call reloadData, it will immediately request the number of sections and rows so that it knows how big it needs to be. It doesn't ask for the cells themselves until it is asked to display itself. Views are automatically displayed as necessary at the beginning of each run loop.
Execution doesn't return to the run loop until your code returns. When you call sleep, you don't execute any code, but you also don't return. This means the run loop doesn't get a chance to display the table, so it never asks for any cells. What you need to do is return from your method and ask that another method gets called in 1 second to remove the doneReminder. An easy way to do this is to use the performSelector:withObject:afterDelay: method. This method adds a timer which will call the method you requested after the given delay, which means you can return to the run loop and let the table display.
doneCell.remName.text=#"BUTTON PRESSED";
[remTable reloadData];
[self performSelector:#selector(removeDoneReminder) withObject:nil afterDelay:1.0];
- (void)removeDoneReminder {
[remList removeObject:doneReminder];
[remTable reloadData];
}
If remlist and remTable are not instance variables, you can use the withObject: parameter to send them to the removeDoneReminder method.
CellForRowAtIndexPath is part of UITableView datasource protocol, make sure that remtable.datasource is point to self
so when you initialize the TableView, you should add
remtable.datasource = self;
i always did this, after
remtable.delegate = self;
Hope this help
Try using delayed performance:
[remtable performSelector:#selector(reloadData) withObject:nil afterDelay:0.1];
Don't know if it will help because I don't know what else you're doing.