【问题标题】:Updating a dictionary inside an array from row selection in UITableView从 UITableView 中的行选择更新数组内的字典
【发布时间】:2012-03-08 17:53:50
【问题描述】:

我有一个来自 JSON 提要的字典数组。这将填充 UITableView。当用户选择一行时,我使用UITableViewCellAccessoryCheckmark,并且我正在尝试修改该行的数组内的字典,因此当滚动后再次重用单元格时,它保持正确。但是我遇到了一个错误。这是我的代码(为清楚起见而缩短):

JSON数据方式:

+ (NSMutableArray *)parseKennelData:(NSString *)type userID:(NSString *)user dogID:(NSString *)dog terms:(NSString *)terms
{
   NSURL *searchURL=[NSURL URLWithString:searchLocation];

   // download and parse the JSON
   NSData *JSONData = [[[NSData alloc] initWithContentsOfURL:searchURL] autorelease ];

   NSError *error=nil;
   CJSONDeserializer *deserializer = [CJSONDeserializer deserializer];
   NSMutableDictionary *JSONdictionary =[deserializer deserializeAsDictionary:JSONData error:&error]; 

   NSMutableArray *allResults = [JSONdictionary valueForKey:@"kennel"];

   return allResults;
}

视图控制器:

interface
{
    NSMutableArray *results;
}

- (void)viewDidLoad
{
    //  data for search
    self.results=[JSONData parseKennelData:@"search" userID:@"demo" dogID:@"" terms:self.terms];
}

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

    NSMutableDictionary *rowData = [self.results objectAtIndex:[indexPath row]];

    UITableViewCell *thisCell = [tableView cellForRowAtIndexPath:indexPath];

    if (thisCell.accessoryType == UITableViewCellAccessoryNone) 
    {        
        thisCell.accessoryType = UITableViewCellAccessoryCheckmark;
        thisCell.accessoryView = [[UIImageView alloc]
                          initWithImage:[UIImage imageNamed:@"tick-button.png"]]; 
        [rowData setObject:@"demo" forKey:@"user_id" ];        
    }
    else
    {
        thisCell.accessoryType = UITableViewCellAccessoryNone;  
        thisCell.accessoryView = [[UIImageView alloc]
                              initWithImage:[UIImage imageNamed:@"plusbutton.png"]];
        [rowData setObject:@"" forKey:@"user_id"];
    }

    [self.results replaceObjectAtIndex:[indexPath row] withObject:rowData];
}

我收到一个 SIGABRT 错误:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'

我想我已经确保我所有的东西都是可变的,所以我看不到它在哪里倒下。

谢谢

【问题讨论】:

  • 你确定 deserializeAsDictionary 返回一个可变字典吗?

标签: ios uitableview nsmutabledictionary didselectrowatindexpath


【解决方案1】:

你说你确保你所有的东西都是不可变的,但是仅仅声明你的 *JSONDictionary*allResults*rowData 指针是可变的并不会使它们可变。这些对象的可变性完全取决于赋值的右侧。

根据您收到的错误,很明显您尝试在didSelectRowAtIndexPath: 中编辑的字典是不可变的。另外,我不熟悉 TouchJSON,但我很确定 allResults 也是不可变的。

要纠正这个问题,您需要进行两项更改,在这两种情况下都使用方便的mutableCopy 方法来制作不可变数组或字典的可变副本。首先,使parseKennelData:userID:dogID:terms:返回的数组可变:

NSMutableArray *allResults = [[JSONdictionary valueForKey:@"kennel"] mutableCopy];

然后,在tableView:didSelectRowAtIndexPath: 中,在修改字典之前制作字典的可变副本:

NSMutableDictionary *rowData = [[self.results objectAtIndex:[indexPath row]] mutableCopy];

【讨论】:

  • 你应该做一个 mutableCopy 以确保它被复制到一个可变对象,例如: NSMutableArray *allResults = [JSONdictionary valueForKey:@"kennel"]mutablCopy];
  • 这还不够:如果你这样做,self.results 将是一个不可变字典的可变数组。
  • 我看到了,我只是展示了如何轻松地制作不可变对象的可变副本作为示例。我不使用 TouchJSON,所以我不能真正说出数据是如何返回的。我应该更清楚地说明这一点。顺便说一句,iOS5 有一个新的 JSON API,这让这件事变得容易多了。谢天谢地,早就该这样了。感谢您的澄清,我不想混淆任何人,这与 SO 的意义相反。
  • 一切都很好:在再次阅读原始问题以确保字典是否也是不可变的时,我找到了完整的解决方案。 :)
  • 非常感谢伙计们——我听说过 mutablecopy,但没有这样想。我习惯了 C#,只是转换成一种格式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-03
  • 1970-01-01
  • 2020-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多