iOS - UITableView Changing Datasourse - iphone

I was wondering if anyone knows how to solve this problem:
I have a UITableview, where the datasource can continue to grow. The issue is when I add elements to the data source, the table cells get messed up.
Each table cell has a text field where the user can enter data into it, but whenever I add data to the datasource the comments replicate to other cells.
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"ImageTableCell";
ImageTableCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
Picture *aPicture = (Picture *) [self.imageData objectAtIndex:[indexPath row]];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ImageTableCell" owner:self options:NULL];
cell = (ImageTableCell *)[nib objectAtIndex:0];
}
NSLog(#"comment %# index %d", aPicture.comment, [indexPath row]);
cell.cellImage.image = aPicture.picture;
cell.commentField.delegate = self;
cell.commentField.text = aPicture.comment;
cell.index = [indexPath row];
cell.tag = [indexPath row];
return cell;
}
self.imagedata is a NSMutabaleArray.
EDIT
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.imageData count];
}
-(void) reloadImages:(NSNotification *) aNotification {
self.imageData = ((AppDelegate *)[[UIApplication sharedApplication] delegate]).currentUserData.images;
[self.imageTableView reloadData];
}
a screenshot http://www.mikerizzello.com/pic.png
Thanks

EDIT:
I think you might have a bad MVC pattern. Here's what I would do:
Take your custom cell, ImageViewCell, and make that class your textField delegate. Add a property for your custom Picture object, and set that in cellForRow...
Then, in your textFieldDelegate methods inside the custom cell class, you can change set the contents of your PictureObject there. I have a feeling that you're handling text input in the viewController, and the index of the data object in your array is getting mixed up and you're applying the comment field text to the wrong item in the array.
EDIT
I think it has something to do with cell reuse. The contents of your cell are not getting wiped out upon reusing a cell.
Try this block before you return the cell:
if (!aPicture.comment) {
cell.commentField.text = #"";
} else {
cell.commentField.text = aPicture.comment;
}

Have you try with
if (cell == nil) {
cell = (ImageTableCell*)[[ImageTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
Anyway you can also set different reuseIdentifier for each of cells but it will be bad idea, I would like to help you but i think need to run this project.
Please let me know if code above give better solution.

Related

dequeueReusableCellWithIdentifier forIndexPath

I have a custom/sub-classed UITableViewCell using NSLayoutConstraints. The left most UIImageView may or may not be populated with an image, and if not, the objects to right of this field will naturally shift to the left. Works well within the custom UITableViewCell, however I'll be populating the content with my custom UITableViewController. Unfortunately, following code will populate every row cell.dispatchedView with an image -- though I've trapped to not populate rows with anything.
This has something to do with the dequeueReusableCellWithIdentifier. Ideas?
static NSString *CellIdentifier = #"CellIdentifier";
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerClass:[NXGActiveUnitsCell class] forCellReuseIdentifier:CellIdentifier];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
NSDictionary *item = [self.model.dataSource objectAtIndex:indexPath.row];
NXGActiveUnitsCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if([[[item objectForKey:#"cfs_no"] clean] length] > 0) {
cell.dispatchedView.image = [UIImage imageNamed:#"p.png"];
NSLog(#">>>%#",[item objectForKey:#"cfs_no"] );
} else {
NSLog(#">>> i got nothing so I should not touch this row...");
}
cell.departmentIconView.image = [UIImage imageNamed:#"f.png"];
cell.unitLabel.text = [item valueForKey:#"unit_id"];
return cell;
}
I don't know if this already solves your problem, but you should
definitely set
cell.dispatchedView.image = nil;
in the else-case, because cells are reused.

How to Add action event work when click on customize list cell button in iphone

Create a Table View.
then create a customize table View cell and place a button on cell and Now I try to get Table View index when click on index.
But when I click on button that place on cell It's not giving me the Index of list.
My Table View class name is SubMenuViewController and cell class name is SubMenuCell
and my code of SubMenuViewController is:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
ModelLocator *model = [ModelLocator getInstance];
static NSString *simpleTableIdentifier = #"SubMenuCell";
SubMenuCell *cell = (SubMenuCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SubMenuCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
if (model.foodSubItemList) {
FoodSubItemVO* foodSubItemTemp = [model.foodSubItemList objectAtIndex:indexPath.row];
[cell.lbSubFoodItem setText: foodSubItemTemp.foodSubItemName];
[cell.lbPrice setText: foodSubItemTemp.price];
[cell setIndexPath:indexPath];
}
return cell;
}
and My SubMenuCell code here
- (IBAction)addItemIntoOrder:(id)sender {
NSLog(#"#%",indexPath);
NSLog(#"#%",indexPath.row);
}
indexPath declare in SubMenuCell.h
Your NSLog's are faulty; try this instead (mind that changed % and # order).
- (IBAction)addItemIntoOrder:(id)sender
{
NSLog(#"%#",indexPath);
NSLog(#"%#",indexPath.row);
}
Make sure that the addItemIntoOrder: action is hooked up to your delegate correctly in IB.

Populating UITableView from NSArray with indexPath.row

I am trying to populate
UITableView in - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method with an array I have initialized in viewDidLoad method.
self.questionsArray = [NSArray arrayWithObjects:#"Q1",#"Q2",#"Q3",#"Q4",#"Q5",#"Q6",#"Q7",#"Q8",#"Q9",#"Q7",#"Q8",#"Q9",#"Q10",#"Q11"];
I understand how to implement various sections and reusing a cell with an identifier. As most of the examples I have seen, I tried like question.text = [NSString stringWithFormat:#"%d. %#", indexPath.row ,[self.questionsArray objectAtIndex:indexPath.row]];
But I am getting like
0. Q1 1. Q2 2. Q3 3. Q4 4. Q5 5. Q6 0. Q1 2. Q2 ....
Please help to load all questions (NSString) to my TableView. I messing up with indexPath.row. Its very difficult to understand. Any tips for best practices to handle indexPath effectively.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case 0:
return [self.questionsArray count];
case 1:
return 1;
default:
return 0;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 0) {
static NSString *QuestionCellIdentifier = #"QuestionCellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:QuestionCellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"QuestionCell" owner:self options:nil];
}
cell = questionCell; // IBoutlet
self.questionCell = nil;
}
question.text = [NSString stringWithFormat:#"%d. %#", indexPath.row ,[self.questionsArray objectAtIndex:indexPath.row]];
return cell;
}
else if (indexPath.section == 1){
static NSString *CustomCellIdentifierMore = #"CustomCellIdentifierMore";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CustomCellIdentifierMore];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifierMore] autorelease];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
switch (indexPath.row) {
case 0:
cell.textLabel.text=#"Select";
break;
default:
break;
}
}
return cell;
}
return nil;
}
cellForRowAtIndexPath is not guaranteed to load cells in order and will be called to update certain cells. You also need to provide the numberOfRowsInSection method, for example:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.tableData count];
}
Are your cells displaying properly or is it just the nslog that is producing confusing output?
Try calling reloadData on your tableView after creating questionsArray in viewDidLoad, so like this:
self.questionsArray = [NSArray arrayWithObjects:#"Q1",#"Q2",#"Q3",#"Q4",#"Q5",#"Q6",#"Q7",#"Q8",#"Q9",#"Q7",#"Q8",#"Q9",#"Q10",#"Q11"];
//or whatever your property for the tableview is called.
[self.tableView reloadData];
Your cellForRowAtIndexPath implementation is a little funky. First, the curly brackets for indexPath.section == 0 condition don't match. Second, I don't see where you are setting the text for cell that you are returning. Whatever you are assigning to question.text should be assigned to cell.textLabel.text. Third, for indexPath.section == 1 condition, you are only setting the text when the cell is nil. The table view is pretty smart about cell management. When a cell goes out of view due to scrolling, it will reuse the cell instead of entirely creating a new one. So, whenever you deque a cell, it may not always be nil. So, you should be setting the cell text outside the if (cell == nil) loop.

dequeueReusableCellWithIdentifier:identifier not picking up a loadNibNamed cell

I have a simple cell - designed in IB - and with the reuseIdentifier set. Below code works quite nicely. HOWever - the NSLog() reveals that the results are never cached.
Table view controller class:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
switch/case for various cell types
{
Foo * item = [results objectAtIndex:indexPath.row];
return [MyCell tableView:tableView populatedCellWith:item];
}
}
MyCell class..
+(UITableViewCell *)tableView:(UITableView *)tableView populatedCellWith:(Foo *)item
{
static NSString * identifier = #"XXX";
MyCell *cell = (MyCell *) [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
NSArray * items = [[NSBundle mainBundle] loadNibNamed:#"MyCell"
owner:self options:nil];
cell = [items objectAtIndex:0];
assert( cell && [cell.reuseIdentifier isEqualToString:identifier]);
NSLog(#"That was a load - rather than a nice cache for %#", self.class);
}
fill out some stuff.
return cell;
}
Why is this - as it makes things a lot more efficient ?
Thanks,
Dw.
The way you create the table view cell can not make sure to put the cell into the reusable queue in table view. Only way to do that is to use
initWithStyle:reuseIdentifier:
Initializes a table cell with a style and a reuse identifier and returns it to the caller.
My another question
Are you sure the cells have been set with a cell identifier? UITableView will not cache those without.

Adding new rows to UITableViewCell

In my application,I will be displaying only one row on the UITableView initially. I want to increase the rows as user loads the previous row with data(an uiimage, here). As now i'm returning value 1, in numberOfRowsInSection: method, since I don't know how to implement it in the required way. Please help.
My cellForRowAtIndexPath: method is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:CustomCellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CustomCellIdentifier ] autorelease];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:self options:nil];
for (id currentObject in nib){
if ([currentObject isKindOfClass:[CustomCell class]]){
cell = (CustomCell *)currentObject;
cell.viewController = self;
break;
}
}
}
if (j<15){
cell.imageView.image = nil;
if (count!=0)
{
#try{
NSInteger row = [indexPath row];
cell.imageView.image = [array objectAtIndex:row];
}
#catch (NSException* ex) {
NSLog(#"doSomethingFancy failed: %#",ex);
}
}
}
cell.showsReorderControl = YES;
return cell;
[array release];
}
that if condition and count is nothing but just for checking the correct functioning of the mutable array, 'array'.
You should read this documentation: http://developer.apple.com/iphone/library/documentation/UserExperience/Conceptual/TableView_iPhone/Introduction/Introduction.html
Have a look to the related samples as well.
Note: in your code [array release] won't be called since you've got a return statement just before it.
When you reach the cellForRowAtIndexPath at a certain indexPath, it means that row is being displayed. If you reach the last row you can insert a new row into the table. To do that, you just need to increase the count that will get returned by the tableView:numberOfRowsInSection function.
I'm guessing your numberOfRowsInSection function will look something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return section==0 ? [array count] : 0;
}
So basically, inside cellForRowAtIndexPath, add the following code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if([indexPath row]==[array count]-1) {
[array addObject:(NEXT_IMAGE)];
}
return cell;
}
You also need to refresh the table. One way is to just call reloadData on your UITableView, but the preferred way is to call beginUpdates/insertRowsAtIndexPaths/endUpdates on the table so that you can show a nice animation of the row being inserted.