表视图崩溃与'*** - [__NSArrayM insertObject:atIndex:]:对象不能为零'

Posted

技术标签:

【中文标题】表视图崩溃与\'*** - [__NSArrayM insertObject:atIndex:]:对象不能为零\'【英文标题】:tableview crash with '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'表视图崩溃与'*** - [__NSArrayM insertObject:atIndex:]:对象不能为零' 【发布时间】:2014-06-01 21:09:22 【问题描述】:

我遇到了问题。 我的 ViewController 中有一个 TableView。这个 TableView 有 5 行带有 textFields。每行的高度为 156 像素。我也有“保存”按钮,单击后我想通过以下方法将所有数据保存到NSMutableArray,但结果出现错误。 我该怎么办? 谢谢

我的方法示例:

- (void) saveDataToArray

    carCellTableViewCell * cell;
    _carNewPrices = [[NSMutableArray alloc] init];
    for (int i = 0; i < 5; i++)
    
        cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath      indexPathForRow:i inSection:0]];
        [_carPrices addObject:cell.priceText.text];
    

这里是 cellForRowAtIndexPath:

- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

carCellTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
cell.nameLabel.text = [_carNames objectAtIndex:indexPath.row];
cell.priceLabel.text = [NSString stringWithFormat:@"$%@/day",[_carPrices objectAtIndex:indexPath.row]];
cell.infoLabl.text = [_carInfos objectAtIndex:indexPath.row];
switch (indexPath.row) 
    case 0:
    
        [cell.img setImage:[UIImage imageNamed:@"rolls.jpg"]];
        return cell;
    
    case 1:
    
        [cell.img setImage:[UIImage imageNamed:@"bentley.jpg"]];
        return cell;
    
    case 2:
    
        [cell.img setImage:[UIImage imageNamed:@"mercedes.jpg"]];
        return cell;
    
    case 3:
    
        [cell.img setImage:[UIImage imageNamed:@"bmw.jpg"]];
        return cell;
    
    case 4:
    
        [cell.img setImage:[UIImage imageNamed:@"skoda.jpg"]];
    
    default:
        break;


return cell;

补充: 在我的 tableviewCell 中,我有一个标签和一个文本字段。当我点击“保存”时,我想保存 textField 中的所有数据并将其发送到标签。

这是 .m 文件中的所有代码:

#import "carListViewController.h"
#import "carCellTableViewCell.h"
#import "UserSingleton.h"
#import "CheckInternetConnection.h"
#define getCarList @"http:mylink.php" //changed
#define setCarList @"http:mylink.php" //changed
@interface carListViewController ()
@property (weak, nonatomic) IBOutlet UIBarButtonItem *editButtonOutler;
- (IBAction)editButtonOnClick:(id)sender;
@property BOOL editOrSave;//0 when edit, 1 when save
@property UserSingleton * userInfo;
@property NSMutableArray *json;
@property NSMutableArray * carNames;
@property NSMutableArray * carPrices;
@property NSMutableArray * carInfos;
@property NSMutableArray * carNewPrices;
- (void) setData;
@property (weak, nonatomic) IBOutlet UITableView *meTableView;
- (void) saveDataToArray;
- (void) getDataOfCars;
@end

@implementation carListViewController


- (void)viewDidLoad

[super viewDidLoad];
self.title = @"List of cars";
// Do any additional setup after loading the view.


- (void) viewWillAppear:(BOOL)animated

CheckInternetConnection * checkInternet = [[CheckInternetConnection alloc] init];
if (![checkInternet isInternetAvailable])
    [self.navigationController popViewControllerAnimated:YES];
_userInfo = [UserSingleton sharedInstance];
if (_userInfo.priority == 2)

    _editButtonOutler.enabled = YES;
    _editButtonOutler.title = @"Edit";

else

    _editButtonOutler.enabled = NO;
    _editButtonOutler.title = @"";

_editOrSave = NO;
[self getDataOfCars];
[_meTableView reloadData];



- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView

    return 1;


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

return 5;


- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

carCellTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
cell.nameLabel.text = [_carNames objectAtIndex:indexPath.row];
cell.priceLabel.text = [NSString stringWithFormat:@"$%@/day",[_carPrices objectAtIndex:indexPath.row]];
cell.infoLabl.text = [_carInfos objectAtIndex:indexPath.row];
switch (indexPath.row) 
    case 0:
    
        [cell.img setImage:[UIImage imageNamed:@"rolls.jpg"]];
        return cell;
    
    case 1:
    
        [cell.img setImage:[UIImage imageNamed:@"bentley.jpg"]];
        return cell;
    
    case 2:
    
        [cell.img setImage:[UIImage imageNamed:@"mercedes.jpg"]];
        return cell;
    
    case 3:
    
        [cell.img setImage:[UIImage imageNamed:@"bmw.jpg"]];
        return cell;
    
    case 4:
    
        [cell.img setImage:[UIImage imageNamed:@"skoda.jpg"]];
    
    default:
        break;


return cell;



- (IBAction)editButtonOnClick:(id)sender 
if (_editOrSave == 0)

    _editOrSave = 1;
    _editButtonOutler.title = @"Save";
    carCellTableViewCell * cell;
    for (int i = 0; i < 5; i ++)
    
        cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
        cell.priceLabel.hidden = YES;
        cell.priceText.hidden = NO;
        cell.priceText.text = [[_json objectAtIndex:i] objectForKey:@"cost"];
    

else if (_editOrSave == 1)

    _editOrSave = 0;
    carCellTableViewCell * cell;
    for (int i = 0; i < 5; i ++)
    
        cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
        cell.priceLabel.hidden = NO;
        cell.priceText.hidden = YES;
        [self saveDataToArray];
        [self setData];
        //cell.priceLabel.text = [_carPrices objectAtIndex:i];
    
    _editButtonOutler.title = @"Edit";

[self getDataOfCars];
[_meTableView reloadData];


- (void) getDataOfCars

_carInfos = [[NSMutableArray alloc] init];
_carNames = [[NSMutableArray alloc] init];
_carPrices = [[NSMutableArray alloc] init];
NSURLRequest* urlRequest =  [NSURLRequest requestWithURL:[NSURL URLWithString:getCarList] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];
_json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
carCellTableViewCell * cell;
for (int i = 0; i < _json.count; i ++)

    cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
    [_carNames addObject:[[_json objectAtIndex:i] objectForKey:@"name"]];
    [_carPrices addObject:[[_json objectAtIndex:i] objectForKey:@"cost"]];
    [_carInfos addObject:[[_json objectAtIndex:i] objectForKey:@"about"]];




- (void) setData
for (int i = 0; i < 5; i ++)

    NSMutableString * postString = [NSMutableString stringWithFormat:setCarList];
    [postString appendString:[NSString stringWithFormat:@"?id=%d", i+1]];
    [postString appendString:[NSString stringWithFormat:@"&cost=%@", [_carPrices objectAtIndex:i]]];
    [postString setString:[postString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:postString]];
    [request setHTTPMethod:@"POST"];
    NSURLConnection * postConnection;
    postConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];




- (void) saveDataToArray

carCellTableViewCell * cell;
_carNewPrices = [[NSMutableArray alloc] init];
for (int i = 0; i < 5; i++)

    cell = (carCellTableViewCell *)[_meTableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
    [_carPrices addObject:cell.priceText.text];




@end

似乎导致了错误,因为并非所有单元格都在屏幕上可见。在我现在向下滚动之后,即使最后一个单元格在我点击编辑按钮后也发生了变化。

如何解决这个问题?

【问题讨论】:

【参考方案1】:

用 UITableView 中的内容填充数组是颠倒的。这样做的方法是相反的。

换句话说,您可以在代码中的其他位置确定 priceText 标签中的内容。如果是静态表,那么信息可能在 IB 中,或者如果您正在实现 tableview:cellForRowAtIndexPath:,那么您正在那里查找 priceText。

将这些值放入 priceArray。

您的修改有帮助。这一行:

[NSString stringWithFormat:@"$%@/day",[_carPrices objectAtIndex:indexPath.row]];

是你的朋友,所以:

NSMutableArray *newArrayOfStrings = [NSMutableArray array];

for (int i=0; i<_carPrices.count; i++) 
    NSString *str = [NSString stringWithFormat:@"$%@/day",_carPrices[i]];
    [newArrayOfStrings addObject:str];

再次编辑。更多代码和 cmets,更清晰:

声明你的vc实现了UITextFieldDelegate,并声明一个属性来保存你编辑的价格:

@interface MyViewController <UITextFieldDelegate>

@property (nonatomic, strong) NSMutableArray *editedStrings;

// initialize this with the carPrices after you get these from JSON
self.editedStrings = [_carPrices mutableCopy];  // if they are NSNumbers

// if they are strings, you'll need a deeper copy:
self.editedStrings = [NSMutableArray array];
for (NSString *str in _carPrices) 
    [self.editedStrings addObject:[str copy]];

在 cellForRowAtIndexPath 中,让你的 vc 成为委托,并标记 textFields,这样你就知道正在编辑哪个:

cell.priceLabel.delegate = self;
cell.priceLabel.tag = indexPath.row;

然后实现用户编辑时的委托方法:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 

    NSInteger index = textField.tag;
    NSString *candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string];
    [self.editedStrings replaceObjectAtIndex:index withObject: candidateString];

    return YES;

【讨论】:

我应该只将文本字段中的值写入我的数组,而不是这样:@"$/day"。只有价格。 取决于你想要什么。看起来您已经有了一组价格(这些是数字?还是字符串?)。 stringWithFormat 代码添加货币单位和 /day。你想要数组中的那些东西吗? 我用我在 .m 文件中编写的所有代码更新我的帖子。 我已经有一个数组,因为我从 json 下载数据,编辑后我想把它上传回来 啊。所以这些是单元格中的文本字段,用户编辑它们,你想得到编辑后的文本吗?啊。您仍然需要数组中的字符串。您需要使您的 vc 成为文本字段的代表,并且当它们应该更改字符范围时,您需要更新数组中的字符串。那么到了上传的时候,这个数组就不需要做任何工作了。【参考方案2】:

[_carPrices addObject:cell.priceText.text] 行添加断点,您会看到在某个索引处,文本将为nil。我无法告诉你为什么它会为零,因为我不知道你是如何创建单元格的。

【讨论】:

我已将 cellForRowAtIndexPath 添加到我的问题中

以上是关于表视图崩溃与'*** - [__NSArrayM insertObject:atIndex:]:对象不能为零'的主要内容,如果未能解决你的问题,请参考以下文章

我们可以通过使用@try,catch 机制来防止崩溃吗?如果错误是 -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty arra

[__NSArrayM objectAtIndex:]: index 2 beyond bounds [0 .. 1]

NSArrayM 在枚举时发生了突变

领域:获取 -[__NSArrayM UTF8String]:无法识别的选择器发送到实例

Facebook JSON 提要 - __NSArrayM insertObject:atIndex:]:对象不能为 nil

-[__NSArrayM objectAtIndex:]:索引 0 超出了带有 userInfo 的空数组的界限(null)