I'm developing a dinamic app in objective-C which parses from a webServer an XML and specifies to my tableView controller how many and which controls (labels, textfields... should print, like a formulary)
The thing is... if my screen can't show all the controls, I use the scroll to navigate through all my scene, til then everything is okay but... When I do that, all my controls (labels, textfields) dissapear!!!Leaving all my tableviewcells empty!!!
If I release the scroll and gets back to original position (on top), all my controls are printed again, but all the information inside textfields is gone.
I guess it is because of a memory thing (weak memory), how can I store all my controls with (strong) like a property to keep them alive
Note: I can't control the amount and type of controls that my webService sends throught the XML...
this is how I do so far:
@property (nonatomic, strong) NSMutableArray *controlsArray;
@property (nonatomic, strong) UITableView *myTableView;
- (void)viewDidLoad
{
[super viewDidLoad];
if ([[UIDevice currentDevice].model hasPrefix:@"iPhone"]){
locationXLabel = 20;
locationXControl = 150;
widthLabel = 130;
}
if ([[UIDevice currentDevice].model hasPrefix:@"iPad"]){
locationXLabel = 65;
locationXControl = 250;
widthLabel = 190;
}
locationYLabel = 10;
locationYControl = 15;
//WebService for printing controls
if (!parBusResponseWebServ) parBusResponseWebServ = [[ParBusResponseWS alloc]imprimePantallaBusqueda];
while ([parBusResponseWebServ transacWebServCompleto] == Nil) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
//if webservice loads incomplete sends this message and exit
if ([[parBusResponseWebServ transacWebServCompleto] isEqualToString:@"FALSE"] ||
[[parBusResponseWebServ controlsList] count] <= 0) {
parBusResponseWebServ = Nil;
return;
}
self.controlsArray = [[NSMutableArray alloc]init];
self.title = @"Búsqueda";
if (!functions) functions = [[Functions alloc]init];
[self createTableView];
}
-(void)createTableView{
//this instance, creates, sets as a delegate and displays tableview
self.myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)style:UITableViewStyleGrouped];
self.myTableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.myTableView.backgroundView = nil;
self.myTableView.backgroundColor = UIColorFromRGB(tableViewBackgroundColor);
self.myTableView.separatorColor = UIColorFromRGB(tableViewSeparatorColor);
self.myTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLineEtched;
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
[self.view addSubview:self.myTableView];
}
//Sets and returns the contents that will have each row of the table
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *cellIdentifier = [NSString stringWithFormat:@"s%i-r%i", indexPath.section, indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
switch (indexPath.section) {
case 0:
{
switch (indexPath.row) {
case 0:{
for (int i = 0; i < [parBusResponseWebServ.controlsList count]; i++) {
if ([[[parBusResponseWebServ.controlsList objectAtIndex:i]tipoControl] isEqualToString:@"TX"]) {
UILabel *label = [functions createLabel:[[parBusResponseWebServ.controlsList objectAtIndex:i] textoControl]
locationX:locationXLabel
locationY:locationYLabel
labelWidth:widthLabel
labelHeight:30
numLabelTag:tagControls
labelAdjustment:UIViewAutoresizingFlexibleRightMargin];
tagControls += 1;
UITextField *textfield = [functions createTextField:@" "
locationX:locationXControl
locationY:locationYControl
textFieldlWidth:150
textFieldHeight:30
keyboardType:UIKeyboardTypeDefault
placeholderText:[[[parBusResponseWebServ.controlsList objectAtIndex:i]requerido] isEqualToString:@"TRUE"] ? @"Requerido***" : @"Introduce Texto"
numTextFieldTag:tagControls
textFieldAdjustment:UIViewAutoresizingFlexibleWidth];
tagControls += 1;
[cell addSubview:label];
[cell addSubview:textfield];
[self.controlsArray addObject:textfield];
locationYControl += 45;
locationYLabel += 45;
}
if ([[[parBusResponseWebServ.controlsList objectAtIndex:i]tipoControl] isEqualToString:@"CB"]) {
UILabel *label = [functions createLabel:[[parBusResponseWebServ.controlsList objectAtIndex:i] textoControl] locationX:locationXLabel locationY:locationYLabel labelWidth:widthLabel labelHeight:30 numLabelTag:tagControls labelAdjustment:UIViewAutoresizingFlexibleRightMargin];
tagControls += 1;
UITextField *campotexto = [functions createTextField:@" "
locationX:locationXControl
locationY:locationYControl
textFieldlWidth:120
textFieldHeight:30
keyboardType:UIKeyboardTypeDefault
placeholderText:@"Seleccione"
numTextFieldTag:tagControls
textFieldAdjustment:UIViewAutoresizingFlexibleWidth];
tagControls += 1;
UIButton *button =[functions createButton:@" "
locationX:270
locationY:locationYLabel
buttonWidth:30
buttonHeight:30
buttonType:UIButtonTypeDetailDisclosure
numButtonTag:tagControls
buttonAdjustment:UIViewAutoresizingFlexibleLeftMargin];
[button addTarget:self action:@selector(action) forControlEvents:(UIControlEvents)UIControlEventTouchUpInside];
[cell addSubview:label];
[cell addSubview:campotexto];
[cell addSubview:button];
[self.controlsArray addObject:campotexto];
locationYControl += 45;
locationYLabel += 45;
}
if ([[[parBusResponseWebServ.controlsList objectAtIndex:i]tipoControl] isEqualToString:@"TA"]){
locationYControl += 30;
UILabel *label = [functions createLabel:[[parBusResponseWebServ.controlsList objectAtIndex:i] textoControl]
locationX:locationXLabel
locationY:locationYLabel
labelWidth:widthLabel
labelHeight:30
numLabelTag:tagControls
labelAdjustment:UIViewAutoresizingFlexibleRightMargin];
tagControls += 1;
UITextView *textView = [functions createTextArea:@" "
locationX:locationXLabel
locationY:locationYControl
textViewlWidth:280
textViewHeight:70
keyboardType:UIKeyboardTypeDefault
numTextViewTag:tagControls
textViewAdjustment:UIViewAutoresizingFlexibleRightMargin];
tagControls += 1;
[cell addSubview:label];
[cell addSubview:textView];
[self.controlsArray addObject:textView];
locationYControl += 135;
locationYLabel += 130;
}
}
}
break;
default:
break;
}
break;
default:
break;
}
}
}
return cell;
}
This most likely happens because your switch is only creating the views for index path (0,0), other index paths are not created...
also you are using cells wrong 1 cell identifier per row, per section? this is not reusing any cell at all (it's not bad but it could be better, arrange by type, etc)
Okay I got it... what happens is that you are only creating elements for the first cell... for the very first cell only (section 0,row 0) you create EVERY CONTROL, and add them as subviews with some offset (that so happens is equal to the label height) this is WRONG.
At the very moment the first row is no longer visible, all your controls disappear (remember they are created for the first row only (they look like they are on other cells but thats because you are pasting them out of the cells bounds...)
What you should be doing is.
YourClass *object = [parBusResponseWebServ.controlsList objectAtIndex:indexPath.row];
//With this object you can create the text
if ([[object tipoControl] isEqualToString:@"TX"]) {
UILabel *label = [functions createLabel:[object textoControl]
locationX:locationXLabel
locationY:locationYLabel
labelWidth:widthLabel
labelHeight:30
numLabelTag:tagControls
labelAdjustment:UIViewAutoresizingFlexibleRightMargin];
UITextField *textfield = [functions createTextField:@" "
locationX:locationXControl
locationY:locationYControl
textFieldlWidth:150
textFieldHeight:30
keyboardType:UIKeyboardTypeDefault
placeholderText:[[object requerido] isEqualToString:@"TRUE"] ? @"Requerido***" : @"Introduce Texto"
numTextFieldTag:tagControls
textFieldAdjustment:UIViewAutoresizingFlexibleWidth];
tagControls += 1;
[cell addSubview:label];
[cell addSubview:textfield];
[self.controlsArray addObject:textfield];
}
Or something like that... also if i can persuade you of this kind of programming... you should not be using labels but the ones that are already on the cell
/*Prior to anything, create a NSMutableDictionary to hold the textfields that you are creating*/
self.textFieldDictionary = [[NSMutableDictionary alloc]init];
On cellForRow
//Use only one reuse identifier (much quicker and less memory intensive)
static NSString *reuseIdentifier = @"cell";
UITableViewCell *cell = tableView dequeue....
if(!cell) {
cell = [UITableViewCell alloc]initWithStyle:....
}
//Remove any other textfield
for (UIView *view in cell.contentView.subviews)
[view removeFromSuperview];
cell.textLabel.text = [object textoControl];
/*Recover previously created TEXTFIELD*/
NSString *key = [[NSNumber numberWithInt:indexPath.row]stringValue];
UITextField *textField = [self.textFieldDictionary objectForKey:key];
if(!textField){
textField = /*Create textfield*/
[self.textFieldDictionary setObject:textField forKey:key]
}
[cell.contentView addSubview:textField]
return cell;
This way you put an element PER row, not all elemnts on a single row (in which case if the row dissapears so will the other elements)
I gave the best answer i can give you... and i hope you use indexPath.. it's your friend (or worst enemy)