and they are taken to another UIViewController (let's call it OtherViewController). In OtherViewController, the name for the selected cell is set. When OtherViewController is dismissed, it updates the cell in MainViewController with the new name:

This all works fine until I have more cells than will fit on the screen. If there are more cells than will fit on the screen (8 for iPhone or 16 for iPad), then this will also set the name for every eighth or sixteenth cell respectively. Any ideas on what I am doing wrong?

4 Answers
4

This is due to cell-reuse and you are mixing up your model with your view (in the MVC context).

A table-cell is a transient thing, once it goes off the screen it is reused (instead of creating new cells) when another cell is needed. This is what the dequeueReusableCellWithIdentifier: method does.

This means you can't store data in there and expect it to still be valid later on. In this example you are trying to store the name in the table cell. The reason to set a property (like the label text) on any view object is purely for display, not for storage. So to solve this problem you should maintain a list of objects in your model (this could be in separate classes or in an array in your mainvc object for example). Then in cellForRowAtIndexPath: you should set the label text every time - even when there should be no label you need to set it to nil or an empty string because the cells are re-used it might contain something from the last time it was used.

Update:
Instead of calling cellForRowAtIndexPath: yourself and setting its text, you should set the text in your model using a method or property in your controller and then tell the table view to reload that cell. The code might look something like this:

// This code is in where you want to set the text from
[mainvc setText:someText forIndexPath:indexPath];

The table view will then call cellForRowAtIndexPath: where the text will be set correctly. This may seem a little convoluted at first, but when you get used to using the Model-View-Controller design pattern you will find that keeping the jobs of each MVC component separate like this will mean your code is tidier, easier to understand, has less bugs, is easier to update/extend, etc.

ok I just tried that and took out my old renaming code, but now the renamed cell does not get renamed until it goes off screen and comes back on, and as soon as that cell is renamed the 8th cell gets renamed too, just like before
–
GarrettJun 30 '12 at 19:32

I fixed the renaming issue by explicitly setting the text to nil if I'm not setting it, however I still have the issue of the cell not updating until going off screen. How would I fix this?
–
GarrettJun 30 '12 at 19:47

You're trying to store data (the new name) in a view (the cell's label). What's probably happening is that when you re-use cells in the data source's cellForRowAtIndexPath method, some of them are ones that have had this text set for them and it's still there.

The better idea is to make your changes in whatever array you use as cell information and then reload the table view to make the changes visible.

As I suppose, you shouldn't call cellForRowAtIndexPath by yourself. It can be called to create cell, not to change it.
You can update your table by passing needed string to the first view via delegate, for example. And on the event (user sets the name) you can update all table and set needed names to cells.