当我添加新的部分(通过步进器)时,部分中的单元格内容与另一部分的内容混合

时间:2013-11-26 19:57:11

标签: ios objective-c uitableview

我有一个带有动态单元格的tableView。每个部分有5行。在每行的前4行中有一个文本字段。相反,在第五行有一个imageview(当我点击这一行时,我可以从我的照片库中选择一张照片,最后一张将被放入imageView)。使用步进器在运行时决定部分的数量。第0部分是固定的,包含一个步进器。当我点击+按钮(在步进器上)时,将添加一个部分。所以一切都是正确的,但如果我之前在包含文本字段的行中写入,然后添加一个或多个部分,这些文本字段的内容将相互混合(以及部分之间)。

//In file.h I've declared @property (nonatomic) int numberOfComponents;

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1 + self.numberOfComponents;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    if (section == 0) {
        return 1;
    }
    else{
        return 4;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == 0) {
        NSString *CellIdentifier = @"cellStepper";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
        UILabel *stepperLabel = (UILabel *)[cell viewWithTag:1];
        stepperLabel.text = [NSString stringWithFormat:@"%i",self.numberOfComponents];
        UIStepper *stepper = (UIStepper *)[cell viewWithTag:2];
        stepper.minimumValue = 0;
        stepper.maximumValue = 20;
        stepper.stepValue = 1;
        stepper.autorepeat = YES;
        stepper.continuous = YES;
        return cell;
    }

    if (indexPath.row == 4) {
        NSString *CellIdentifier = @"cellProfileSnap";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

        return cell;
    }

    NSString *CellIdentifier = @"cellDetail";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    UITextField *cellLabelComponent = (UITextField *)[cell viewWithTag:3];
    cellLabelComponent.placeholder = @"detail";
    return cell;
}

- (IBAction)stepperClik:(UIStepper *)stepper{
    if (stepper.value == 0 && self.numberOfComponents == 0) {
        if (stepper.value > self.numberOfComponents) {
            self.numberOfComponents += 1;

        }
        else{
            return;
        }
    }


    if (stepper.value > self.numberOfComponents) {
        self.numberOfComponents += 1;

    }
    else{
        self.numberOfComponents -= 1;

    }


    [self.tableView reloadData];

}

enter image description here

enter image description here

由Greg解决,但现在还有另一个问题:我有一个保存按钮,它应该将许多数组保存到字典中(包含每个部分5的详细信息)作为部分的数量。 这里是保存按钮的代码:

- (IBAction)saveButton:(id)sender{

    NSMutableArray *arrComponents = [[NSMutableArray alloc] init];
for (int i = 0; i < self.numberOfComponents; i++)
{
    NSMutableArray *component = [[NSMutableArray alloc] init];
    for (int j = 0; j < [self.arrDetails count]; j++)
    {
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:j inSection:i+1];
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath: indexPath];
        if (j == 4){
            UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
            NSLog(@"%@",imageComponent.image);
            if (imageComponent.image == Nil) {
                [component addObject: nil];
            }
            [component addObject: imageComponent.image];
        }
        else{
            UITextField *detailComponent = (UITextField *) [cell viewWithTag:3];
            NSLog(@"%@",detailComponent.text);
            if ([detailComponent.text isEqualToString:@""]) {
                [component addObject:@""];
            }
            if (detailComponent.text != nil && i != 0)
                [component addObject: detailComponent.text];
        }

    }
    [arrComponents addObject: component];
    NSLog(@"%@",arrComponents);
}

在代码中显示它/ / ERROR HERE,在最近一次迭代(最后一节读取)的第5次迭代(部分中的行数)的第四次迭代中,应用程序崩溃,给出了这条消息:

  

由于未捕获的异常而终止应用   'NSInvalidArgumentException',原因:'*** - [__ NSArrayM   insertObject:atIndex:]:object不能为nil'

2 个答案:

答案 0 :(得分:1)

之所以发生这种情况,是因为您没有保存cellLabelComponent.text属性,并且当您重新加载Data tableView时会重用单元格(这会导致此问题)。 您应该将输入的数据保存到cellLabelComponent(例如,在数组中,您可以使用UITextFieldDelegate),并在您的cellForRowAtIndexPath:方法中将保存的值保存到所需的字段。

// EXTENDED

符合.h文件或类扩展中的<UITextFieldDelegate>协议。 添加

@property (nonatomic, strong) NSMutableDictionary *textValueDictionary;

到您的类扩展,并在viewDidLoad或init方法中分配它和init:

self.textValueDictionary = [[NSMutableDictionary alloc] init];

将其添加到cellForRowArIndexPath:

    cellLabelComponent.placeholder = @"detail";
    // Make your class to be delegate for UITextField
    cellLabelComponent.delegate = self;
    // I use NSString (section) as a key in my dictionary. You can use NSNumber if you like
    if (self.textValueDictionary[[NSString stringWithFormat:@"%d", indexPath.section]])
        cellLabelComponent.text = self.textValueDictionary[[NSString stringWithFormat:@"%d", indexPath.section]];
    else
        cellLabelComponent.text = @""; //Your default value

添加您的UITextFieldDelegate方法:

- (void)textFieldDidEndEditing:(UITextField *)textField
{
    // Get reference to the cell
    UITableViewCell *cell = (UITableViewCell*)[[[textField superview] superview] superview];
    // Get index path
    NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];

    // Get section as a string
    NSString *section = [NSString stringWithFormat:@"%d", indexPath.section];
    [self.textValueDictionary setValue:textField.text forKey:section];
}

如果需要,您可以使用更多委托。 它应该足以使它工作。它只会在你的表部分中有一个UITextField时工作,如果你有更多你应该在你的字典中使用唯一键(如果你在部分中有更多的那个文本字段,但NSindexPath将工作,但只记得转换,它将起作用)它到NSNumber)。 让我知道它是否有效。

// EXTENDED

如果每个部分有更多的UITextField,则必须更改字典键。只要每个部分最多有一行,上面的解决方案就可以正常工作。

如果每个部分有多个文本字段但每个单元格不超过一个文本字段(这也适用于每个部分的一个文本字段),则此解决方案(如下所示)将起作用: 从:

更改cellForRowAtIndexPath中的行
if (self.textValueDictionary[[NSString stringWithFormat:@"%d", indexPath.section]])
    cellLabelComponent.text = self.textValueDictionary[[NSString stringWithFormat:@"%d", indexPath.section]];

为:

NSString *key = [NSString stringWithFormat:@"sec:%d,row:%d", indexPath.section, indexPath.row];
if (self.textValueDictionary[key])
    cellLabelComponent.text = self.textValueDictionary[key];

并更改textFieldDidEndEditing:方法中的行:

NSString *section = [NSString stringWithFormat:@"%d", indexPath.section];
[self.textValueDictionary setValue:textField.text forKey:section];

为:

NSString *key = [NSString stringWithFormat:@"sec:%d,row:%d", indexPath.section, indexPath.row];
[self.textValueDictionary setValue:textField.text forKey:key];

答案 1 :(得分:1)

我相信你的detailComponent等于nil,你不能将nil保存到数组中。在你打电话之前

[component addObject: detailComponent.text]; //ERROR HERE

做检查:

if (detailComponent != nil && i != 0)
    [component addObject: detailComponent.text]; 

可能会发生这种情况,因为在您的第0部分中您没有任何文本字段。

// EDITED

这个问题发生在这里:

if (imageComponent.image == Nil) {
    [component addObject: nil];
}
[component addObject: imageComponent.image];

将其替换为:

if (imageComponent.image == nil) {
    [component addObject:[NSNull null]];
}
else {
    [component addObject: imageComponent.image];
}

如果要添加nil,则无法将nil添加到数组中,您应该添加对象NSNull。 你错过了其他声明。您的代码尝试在if语句中首次将nil添加到数组中两次(如果图像为nil)([component addObject:nil];),并在if语句之后第二次:[component addObject:imageComponent.image];

// EDITED

按照以下代码中的评论建议进行更改。我使用相同的字典,您应该更改名称,因为它表明它只保留textfields值,但现在它也将存储图像:

    if (indexPath.row == 4) {
        NSString *CellIdentifier = @"cellProfileSnap";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

        //I believe this is where you keep your imageView
        // get your image 
        UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];
        NSString *key = [NSString stringWithFormat:@"sec:%d,row:%d", indexPath.section, indexPath.row];
        if (self.textValueDictionary[key])
            imageComponent.image = self.textValueDictionary[key];
        else
            imageComponent.image = nil; //Your default value (probably you want to set up your plus image)
        return cell;
    }

您需要做的下一步是用户按下加号图像 - 您必须将图像保存在字典中。将此代码放在您从用户处获取图像的方法中。这是一个伪代码,所以你必须稍微调整一下:

// Get reference to the cell
    UITableViewCell *cell = //have a look on textFieldDidEndEditing  method. You have to work out how to get the cell (I cannot do that because I haven't got access to your code);
    // Get index path
    NSIndexPath *indexPath = [self.myTableView indexPathForCell:cell];

    // Get section as a string
    NSString *key = [NSString stringWithFormat:@"sec:%d,row:%d", indexPath.section, indexPath.row];
    UIImage *img = //get your image here;
    //make sure it's not nil before you save it to dictionary
    //save it to dictionary
    [self.textValueDictionary setValue:img forKey:key];

最后一位是saveButton:我昨天的建议中有错误的方法。您正试图直接从单元格获取文本和图像,如果单元格可见,它可以正常工作。如果你看不到细胞系统把它放到可重复使用的池中,你会得到nils。 要修复它,你必须从字典中获取数据: 不要使用:

  UIImageView *imageComponent = (UIImageView *) [cell viewWithTag:4];

代替:

NSString *key = [NSString stringWithFormat:@"sec:%d,row:%d", indexPath.section, indexPath.row];
    UIImage *img = self.textValueDictionary[key];
    // make sure is not nil before you save it. If it's nil add [NSNull nil] to your array as I explained before.

当你阅读文字时,不要这样做:

UITextField *detailComponent = (UITextField *) [cell viewWithTag:3];

从字典中获取文字:

     NSString *key = [NSString stringWithFormat:@"sec:%d,row:%d", indexPath.section, indexPath.row];
        NSString *str = self.textValueDictionary[key];

如果它抱怨数据类型使用cast(UIImage *)。 请记住将您的第一个循环更改为:for(int i = 1; i&lt; self.numberOfComponents; i ++),当您获得NSIndexPath时,将其更改为inSection:i而不是inSection:i + 1。 我没有在Xcode中运行它,所以可能有一些错误,但你应该能够找到并修复它。 希望它对你有用。