PDA

View Full Version : Two tableview cell codes ... one works, the other doesn't ... why?




multinode
Sep 23, 2012, 10:10 PM
This tableview cell code works, i.e. displays my array of session strings:

@interface OrderFormController : UITableViewController <UITextFieldDelegate>

@property (nonatomic, retain) NSMutableArray *tableData;
@property (nonatomic, retain) NSMutableArray *sessions;
@property (nonatomic, retain) NSString *individualSession;
@property (nonatomic, retain) UITableViewCell *cell;

@end


@implementation OrderFormController

@synthesize tableData = _tableData;
@synthesize sessions = _sessions;
@synthesize individualSession = _individualSession;
@synthesize cell = _cell;

- (void)viewDidLoad {
[super viewDidLoad];

self.tableData = [[NSMutableArray alloc]initWithArray:self.sessions];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";

self.cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (self.cell == nil) {
self.cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

// Configure the cell...
self.individualSession = [self.tableData objectAtIndex:indexPath.row];

UITextField *cellText = [[UITextField alloc]initWithFrame:CGRectMake(10, 10, 768, 31)]; //cellText is local to this function
cellText.text = self.individualSession;

[self.cell.contentView addSubview:cellText];

return self.cell;
}

@end


.................................

This code does not work, i.e. blank cells except last one ... why?:

@interface OrderFormController : UITableViewController <UITextFieldDelegate>

@property (nonatomic, retain) NSMutableArray *tableData;
@property (nonatomic, retain) NSMutableArray *sessions;
@property (nonatomic, retain) NSString *individualSession;
@property (nonatomic, retain) UITableViewCell *cell;
@property (nonatomic, retain) UITextField *cellTxt;

@end

@implementation OrderFormController

@synthesize tableData = _tableData;
@synthesize sessions = _sessions;
@synthesize individualSession = _individualSession;
@synthesize cell = _cell;
@synthesize cellTxt = _cellTxt;

- (void)viewDidLoad {
[super viewDidLoad];

self.tableData = [[NSMutableArray alloc]initWithArray:self.sessions];

self.cellTxt = [[UITextField alloc]initWithFrame:CGRectMake(10, 10, 768, 31)];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";

self.cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (self.cell == nil) {
self.cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

// Configure the cell...
self.individualSession = [self.tableData objectAtIndex:indexPath.row];

self.cellTxt.text = self.individualSession; //cellTxt is global to this class

[self.cell.contentView addSubview:self.cellTxt];

return self.cell;
}

@end



PhoneyDeveloper
Sep 24, 2012, 07:21 AM
Having a global textField doesn't make any sense. Also, having a global tableViewCell doesn't make sense. Adding a single view as a subview to a number of superViews ends up with the subview in only one superview; the last one that it's added to.

Why don't you do this the normal way?

ArtOfWarfare
Sep 24, 2012, 10:17 PM
Now I'm crap at memory management, but I'm pretty sure both of your examples are handling memory incorrectly.

In your first example, you call alloc/init to get a new UITextField each time a UITableViewCell comes onto screen. The whole idea behind reusable cell identifiers is, however, is that you don't have to do that. Each time a cell vanishes off of screen, it is "recycled" and made into the next cell that is needed. Thus a list of hundreds of cells can be made when only ~10 need to be allocated in memory.

You should only call alloc/init to get a new UITextField each time a new UITableViewCell is made. You must then find some way of reusing these cells. Your options are to use tags (messy and very Android-ish... basically you'll be playing with magic numbers (http://en.wikipedia.org/wiki/Magic_number_(programming)), which is a bad idea for code maintain- and read-ability,) or to just subclass UITableViewCell so that you can utilize properties.

Also, I was surprised that you haven't been noticing overlapping text, but now that I think about it, UITextField probably has an opaque white background and since you're assigning them all to have the same size and position, you're probably perfectly covering up prior text with new text.

In your second example, you don't call for a new UITextField often enough. You call for it just once, in ViewDidLoad. But you want more than one to appear on screen. Thus, you're always dealing with the same instance. When you assign that one instance to have a cell as a superview, it gets removed from whichever view it was in before, because, though a view may have multiple children, it can only have one parent. Thus the label will only appear at the last cell that appears on screen (the top one if you're scrolling up, the last one if you're scrolling down... one in the middle if you're adding/removing cells from the middle, I suppose...)

If you'd like, you can think of it as like telling a single child to sit at one desk in a classroom, and then another, and then another, until eventually the child has sat at every desk. Each time the child has to get up and move. In the end, though every desk had a child sitting at it at one point or another, the child is still sitting at only one desk: the last desk you told it to sit at.

multinode
Sep 25, 2012, 01:57 AM
Hi AOW ...

Thanx ... very helpful. I now understand what was wrong with the second coding example. I still don't know completely how to implement the UITextField creation per your suggestion ... more thinking necessary.

Btw, I need to retrieve the UITextField corresponding to a given cell (still visible) after it's been added as a subview to the cell's contentView. I need this in another part of my code as follows:

When my tableview cells are set into normal editing mode, i.e. delete marks or insertion mark at the left end of each row, the following method will be called:


-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.tableView.editing) return YES;
//I want "enable" the corresponding UITextField to allow in place editing of the particular row <----
return NO;
}


I've solved the in-place editing problem and I'll post my complete solution in a couple of days.