James Finley
James Finley

Reputation: 485

UITableView for Forms Crashes

I have a UITableViewController that I'm using for a form. Each cell has a UILabel and a UITextField. When I tap on a UITextField, the keyboard comes up, then I scroll down and the cell goes off screen, when I tap on another UITextField, the app crashes.

This is my cell subclass.

@implementation EditorFieldCell

- (id)init
{
    self = [super init];
    if (self) {
        self.selectionStyle = UITableViewCellSelectionStyleNone;

        [self.contentView addSubview:self.nameLabel];
        [self.contentView addSubview:self.textField];
    }
    return self;
}

- (void)setName:(NSString *)name
{
    _name = name;

    CGRect frame = self.nameLabel.frame;
    frame.size.width = roundf([_name sizeWithFont:[UIFont boldSystemFontOfSize:17.0f]].width);
    self.nameLabel.frame = frame;

    frame = self.textField.frame;
    frame.size.width = self.frame.size.width - 16.0f - 14.0f - 14.0f - self.nameLabel.frame.size.width;
    frame.origin.x = 16.0f + 14.0f + self.nameLabel.frame.size.width;
    self.textField.frame = frame;

    self.nameLabel.text = _name;
}

- (void)setPlaceholder:(NSString *)placeholder
{
    _placeholder = placeholder;

    self.textField.placeholder = placeholder;
}

- (void)setText:(NSString *)text
{
    _text = text;

    self.textField.text = text;
}

- (UILabel*)nameLabel
{
    if (_nameLabel)
    {
        return _nameLabel;
    }

    _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(16.0f, 0.0f, 0.0f, self.frame.size.height)];
    _nameLabel.font = [UIFont boldSystemFontOfSize:17.0f];
    return _nameLabel;
}

- (UITextField*)textField
{
    if (_textField)
    {
        return _textField;
    }

    _textField = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 0.0f, self.frame.size.height)];
    _textField.font = [UIFont systemFontOfSize:17.0f];
    _textField.textAlignment = NSTextAlignmentRight;
    _textField.keyboardAppearance = UIKeyboardAppearanceDark;
    return _textField;
}

@end

And here is my table subclass.

@interface ManageWineViewController ()

@end

@implementation ManageWineViewController

- (id)init
{
    self = [super initWithStyle:UITableViewStyleGrouped];
    if (self) {
        self.title = @"Manage Wine";
        self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(done)];
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(save)];

        NSMutableArray *data = [[NSMutableArray alloc] init];

        NSMutableDictionary *section = [[NSMutableDictionary alloc] init];
        NSMutableArray *sectionData = [[NSMutableArray alloc] init];

        [sectionData addObject:@{@"name": @"Estate", @"placeholder": @""}];
        [sectionData addObject:@{@"name": @"Wine", @"placeholder": @""}];
        [sectionData addObject:@{@"name": @"Vintage", @"placeholder": @"", @"keyboardType": [NSNumber numberWithInt:UIKeyboardTypeDecimalPad]}];
        [section setObject:sectionData forKey:@"data"];

        [data addObject:section];

        section = [[NSMutableDictionary alloc] init];
        sectionData = [[NSMutableArray alloc] init];

        [sectionData addObject:@{@"name": @"Type"}];
        [sectionData addObject:@{@"name": @"Style", @"placeholder": @"Select a Style", @"options": @[@"", @"Red", @"White", @"Rosé", @"Sparkling", @"Saké", @"Dessert, Sherry, and Port"]}];
        [sectionData addObject:@{@"name": @"Appellation", @"placeholder": @""}];
        [section setObject:sectionData forKey:@"data"];

        [data addObject:section];

        section = [[NSMutableDictionary alloc] init];
        sectionData = [[NSMutableArray alloc] init];

        [sectionData addObject:@{@"name": @"Alcohol %", @"placeholder": @"", @"keyboardType": [NSNumber numberWithInt:UIKeyboardTypeDecimalPad]}];
        [section setObject:sectionData forKey:@"data"];

        [data addObject:section];

        self.data = data;

        self.inputTexts = [[NSMutableDictionary alloc] initWithDictionary:@{@"0": @"",
                                                                            @"1": @"",
                                                                            @"2": @"",
                                                                            @"10": @"",
                                                                            @"11": @"",
                                                                            @"12": @"",
                                                                            @"20": @""}];
    }
    return self;
}

- (void)done
{
    [self.currentTextField resignFirstResponder];

    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}

- (void)save
{
    [self done];
}

- (void)hidePicker
{
    [self.selectActionSheet dismissWithClickedButtonIndex:0 animated:YES];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return self.data.count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return ((NSArray*)[[self.data objectAtIndex:section] objectForKey:@"data"]).count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary *cellInfo = [((NSArray*)[[self.data objectAtIndex:indexPath.section] objectForKey:@"data"]) objectAtIndex:indexPath.row];

    static NSString *CellIdentifier = @"EditorCell";
    EditorFieldCell *cell = (EditorFieldCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (!cell)
    {
        cell = [[EditorFieldCell alloc] init];
    }

    cell.textField.tag = [[NSString stringWithFormat:@"%i%i", indexPath.section, indexPath.row] integerValue];
    cell.textField.delegate = self;

    cell.name = cellInfo[@"name"];
    cell.placeholder = cellInfo[@"placeholder"];
    cell.text = [self.inputTexts objectForKey:[NSString stringWithFormat:@"%i", cell.textField.tag]];

    if (cellInfo[@"keyboardType"])
    {
        cell.textField.keyboardType = [cellInfo[@"keyboardType"] integerValue];
    }
    else
    {
        cell.textField.keyboardType = UIKeyboardTypeDefault;
    }

    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}

#pragma mark - UITextFieldDelegate methods
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    self.currentTextField = textField;

    if (textField.tag == 11)
    {
        //show select
        NSArray *options = [[[[self.data objectAtIndex:1] objectForKey:@"data"] objectAtIndex:1] objectForKey:@"options"];
        self.selectTextField = textField;
        self.selectOptions = options;

        [textField resignFirstResponder];

        self.selectActionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];

        CGRect pickerFrame = CGRectMake(0, 40, 0, 0);

        self.selectPickerView = [[UIPickerView alloc] initWithFrame:pickerFrame];
        self.selectPickerView.showsSelectionIndicator = YES;
        self.selectPickerView.dataSource = self;
        self.selectPickerView.delegate = self;

        [self.selectActionSheet addSubview:self.selectPickerView];
        [self.selectActionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
        [self.selectActionSheet setBounds:CGRectMake(0, 0, 320, 485)];
    }
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
    [self.inputTexts setObject:textField.text forKey:[NSString stringWithFormat:@"%i", textField.tag]];
    return YES;
}

@end

The error that I am getting with the crash is:

*** -[EditorFieldCell _didChangeToFirstResponder:]: message sent to deallocated instance 0x155f6e20

This is iOS 7 (and will only support iOS 7) if that helps.

Upvotes: 1

Views: 471

Answers (1)

Bhumeshwer katre
Bhumeshwer katre

Reputation: 4671

You are not initialising EditorFieldCell with reuse identifier.

   EditorFieldCell *cell = (EditorFieldCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

This condition will false.

   if (!cell)
     {
         cell = [[EditorFieldCell alloc] init];
     }

Try to create cell with reuseIdentifier

cell = [[EditorFieldCell alloc] initWithStyle:UITableViewCellStyleDefault
                                          reuseIdentifier:CellIdentifier];

And write this in EditorFieldCell.m

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    if (self == [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
           self.selectionStyle = UITableViewCellSelectionStyleNone;

           [self.contentView addSubview:self.nameLabel];
           [self.contentView addSubview:self.textField];
    }

}

Upvotes: 2

Related Questions