如何从提取的结果对象填充稀疏的UITableView?

时间:2012-07-01 04:35:51

标签: objective-c cocoa-touch uitableview core-data

在我的甜蜜应用程序中,您可以使用项目列表中的两种项目。有物品和袋子物品。导航到清单屏幕时,表视图有两个部分,每个部分有4个单元格。四个单元格用于装备物品,四个单元格用于“包”中的物品。如果你没有装备任何东西,细胞就会说“空”。

如何根据结果对象的形状有条件地填充表格单元格?

以下是我希望的代码:

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

  static NSString *CellIdentifier = @"Cell";

  UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

  if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
  }

  // this returns 'nil' if the index path was out of bounds
  NSManagedObject * item = [self.fetchedResultsController carefullyGetObjectAtIndexPath:indexPath];

  if (nil == item) {
    cell.textLabel.text = @"empty"; 

  } else {
    cell.textLabel.text = [item valueForKey:@"name"];

  }

} 

我在尝试实现这个'小心'objectAtIndexPath:

时遇到了一些问题

我尝试了边界检查,但我遇到了麻烦,因为fetchedArray是平的,而我试图导航的概念模型并不平坦:行是'in'部分。

我尝试使用try / catch,但后来我记得越界的元素是未定义的,而不是nil ...所以有时我得到一个错误,我可以捕捉并做出反应,有时我只是得到随机有趣的东西。我现在的设置:

@try {

  NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];

  return managedObject;
}
@catch (NSException * e) {
  return nil;
}

一直给我5个条目,4个在正确的位置,1个奇数球,这是另一个部分的重复。

不确定如何手动导航所提取的结果。我正在玩四种,每种都有两种。我曾希望它会像双重嵌套数组一样容易,外部的部分和内部的行。似乎事情比这更棘手。当我检查fetchedResults NSArray时,我发现它是扁平的。所有的“包”物品都是第一个,“装备”是下一个。我不认为我可以依赖这种顺序,所以我觉得使用映射函数从indexPath部分到数组索引是不安全的。 (我可以确信这对此感到安全。)

我想到的一个替代方法是将8个“空”项目填充到我的库存中,当这些部分未完全填满时,这些项目将作为占位符结果返回。但这并不适合我。

我意识到为什么这不起作用:表不应该有'空'行。但我希望我的桌子有空行!

更新

这是我现在使用的方法......

- (NSManagedObject*) carefullyGetObjectAtIndexPath:(NSIndexPath*)indexPath 
{
  NSLog(@"in %@ %s", [self class], _cmd);

  NSString * desiredType = (indexPath.section == BAG_SECTION)? @"bag" : @"equipable";
  NSArray * fetchedObjects = [self.fetchedResultsController fetchedObjects];
  NSInteger sectionStartIndex = -1;

  // iterate until you hit a type you like
  NSUInteger i, count = [fetchedObjects count];
  for (i = 0; i < count; i++) {
    NSObject * obj = [fetchedObjects objectAtIndex:i];
    NSString * fetchedType = (NSString*)[obj valueForKey:@"type"];

    if ([desiredType isEqualToString:fetchedType]) {
      sectionStartIndex = i;
      break;
    }
  }

  if (-1 == sectionStartIndex) {
    // maybe there aren't any of that type of item

  } else {

    NSInteger calculatedEntityIndex = sectionStartIndex + indexPath.row;
    NSLog(@"calculated index %d", calculatedEntityIndex);

    // if we are still in the array
    if (calculatedEntityIndex < [fetchedObjects count]) {

      // then we can get the object
      NSManagedObject * entity = [fetchedObjects objectAtIndex:calculatedEntityIndex];

      // and if we are still in the right section
      NSString * typeForEntityAtIndex = [entity valueForKey:@"type"];

      if ([desiredType isEqualToString:typeForEntityAtIndex]) {
        // then this is what we wanted

        return entity;
      }
    }
  }

  return nil;   
}

我真的不觉得我应该迭代这样的事情......

Ž。

完全披露:这是一个学期项目,但该项目是以任何必要的方式制作应用程序。这包括第三方图书馆,在stackoverflow上提问,&amp; c ...这个学期项目的目标是体验更大的事情,比如甜蜜的应用程序,而不是学习目标-c。

1 个答案:

答案 0 :(得分:1)

齐格,

NSFetchedResultsController有很多限制。如果您无法使您的架构满足其严格的要求而且看起来您可能没有,那么您应该构建多个tableView中的NSFetchRequest。这很简单。大多数有趣的tableView都是这样做的。当您执行更大的提取然后使用集合类上的set和filter操作优化搜索时,Core Data确实最有效。

tableView可以有空行。您只需要在各种委托和单元配置代码中使用自定义代码进行协调。

您有很多选择来解决您的问题。看来你对一个非常有限的框架API不满意。你是一个崭露头角的程序员。滚动你自己。

安德鲁

P.S。您有一个好奇的目标是编写Mac OS X / iOS应用程序而无需学习Objective-C。实际上,您已经选择了框架中的一种技术Core Data,它可以将Objective-C运用到其最大功能。 (在我看来,作为iOS程序员的教育者,你的教育可能会更好地学习一个非常不同的持久性模型,Core Data的模型的复杂性,而不是退回到平凡的主流SQL解决方案。)如果你更愿意使用不同的语言,MacRuby / RubyMotion非常有效。