reloadData calls numberOfSections, numberOfRows, not cellForRowAtIndexPath - objective-c

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.

Related

OSX NSTableView insertRowAtIndexes

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];

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.

Incorrect indexPath against UITableView after calling reloadData from textFieldDidEndEditing

So I'm trying to emulate the way in which the standard Apple code works on the contacts app when managing telephone numbers. Specifically here, I'm working on deleting a row from a tableview if its empty and the user navigates to any other row
My problem is that as the tableview reload causes the UITextField to resign its responder, I need to set the responder again for the text field navigated to by the user
I have the UITextField delegate and am handling the usual textFieldShouldBeginEditing , textFieldDidBeginEditing , textFieldShouldEndEditing , textFieldDidEndEditing
In order to handle the functionality, my code is within textFieldDidEndEditing, whereby I remove the data from the tableview array, and as the tableview has 2 sections, I am calling:
[MyTableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
During textFieldDidBeginEditing I save the indexPath of the textField being edited using:
EditableCustomCell *textFieldCell = (EditableCustomCell *)[[textField superview] superview];
NSIndexPath *indexPath = [MyTableView indexPathForCell:(EditableCustomCell *)textFieldCell];
responderIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
I then use the following code to set the correct rows textField to be the first responder:
EditableCustomCell *customCell = (EditableCustomCell *)[MyTableView cellForRowAtIndexPath:responderIndexPath];
[customCell.editableTextField becomeFirstResponder];
Everything seems fine until near the end of the processing, when all of a sudden textFieldDidBeginEditing starts to return section 0 row 0 for the indexPath (even though when examining the tag value or text contained return the correct values for the textfield)
Below is a log from the start of the process explained above:
- textFieldDidEndEditing started <-- start of delete processing
- textFieldDidEndEditing - tableviewData - replacing object at index 1
CustomTableViewController.deleteRow - delete called for indexPath section 1 ... row 1
- reloading MyTableView
- CustomTableViewController-cellForRowAtIndexPath started
CustomTableViewController-cellForRowAtIndexPath section=1 row=0
CustomTableViewController-cellForRowAtIndexPath ending
CustomTableViewController-cellForRowAtIndexPath section=1 row=1
CustomTableViewController-cellForRowAtIndexPath ending
CustomTableViewController-cellForRowAtIndexPath section=1 row=2
CustomTableViewController-cellForRowAtIndexPath ending
- textFieldShouldBeginEditing started
indexPath for textFieldShouldBeginEditing is : section 1 row 1
- textFieldShouldBeginEditing ending
- textFieldDidBeginEditing started
indexPath for textFieldDidBeginEditing is : section 1 row 1 text 3 tag 1
- textFieldDidBeginEditing ending
- textFieldDidEndEditing ending <-- end of delete processing
- textFieldDidBeginEditing started
- textFieldDidBeginEditing ... setting responderIndexPath section 0 row 0
indexPath for textFieldDidBeginEditing is : section 0 row 0 text 123 tag 0
- textFieldDidBeginEditing ending
As can be seen from the last part of the log, after textFieldDidEndEditing completes, textFieldDidBeginEditing is called but returns section 0 and row 0 (the rows stay displayed and visible throughout)
I can neither understand why this is called, or why it is not returning the correct indexPath. As can be seen, the text is returned for the value (in this case the entered value of 123) and I have verified this with other data and other rows (for both text and tag for the textfield)
Perhaps my setting of becomeFirstReponsder within textFieldDidEndEditing is incorrect, although if that's true, I'm at a loss as to where to process this
Hoping someone out there with a better understanding of this can help me out, as you can tell, I've been through this for several hours without any resolution
Thanks
Izzy
EDIT 1: In the code, all that is called is becomeFirstReponder before textFieldDidEndEditing completes. When you look at the log after cellForRowAtIndexPath has completed, it enters and exists the textfield TWICE, once for the row that was below the row just removed, and then again when it returns 0 for the section/row of the indexPath ? I am failing to understand what sequence of events is causing this post table reload firing of methods
EDIT 2: Is it just me, or does it seem really strange that there is NO textfieldSHOULDbeginEditing prior to the textFieldDidBeginEditing at the end of the log ? Is it that I am screwing with the internal process by reloading the table during textFieldDidEndEditing ? Is there a better place to do this (ie. remove a row and reload the tableview to show the UI update) ?
OK, to answer my own question ...
After alot of debugging, it seems that ...
I'm inteferring with the standard UI workflow by reloading the tableview during textfieldDidEndEditing
Calling reloaddata destroys the tableview cells (and all objects contained within the cells ie. UITextFields, UILabels, etc) and recreates them, causing
By moving this call out to a standalone button, it functioned as expected without the indexPath returning 0 (I still dont fully understand the call stack when it gets to this point, but hey)
Now my BIG problem is deciding when to programatically call the reload, as I want it driven off the event of leaving the text field ... I feel another question coming on :\
Hope my ramblings help someone out in the future that tries to do a similar thing ...

UIPickerView Spin Confusion

I have an app that I am currently making that has a PickerView and a UIButton. I want the user to tap the button and make the picker view show a random selection. I have been looking around and can't seem to come up with anything. I guess it would be similar to the Urbanspoon app. I know it is just a piece of a code but I can't think of what it could be.
You are looking for – selectRow:inComponent:animated:
So do something like this:
[thePickerView selectRow:(arc4random() % numRows) inComponent:0 animated:YES];
where numRows is the number of rows. If the rows are associated with an array names rowArray for instance it would be:
[thePickerView selectRow:(arc4random() % [rowArray count]) inComponent:0 animated:YES];
So, upon pressing the button you would randomly choose an item from the data source of your PickerView and then call – selectRow:inComponent:animated: on your PickerView.