【问题标题】:UICollectionView with Multiple subclassed UICollectionViewCell具有多个子类 UICollectionViewCell 的 UICollectionView
【发布时间】:2013-03-18 02:39:09
【问题描述】:

我的 UICollectionView 中有多个按“datasetType”分组的部分。

我还为每个部分定制了一个 UICollectionViewCell。

如何确定cellForItemAtIndexPath 方法中我需要哪个自定义UICollectionViewCell

我的第一个想法是基于[sectionInfo name]

id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:indexPath.section];

if ([[sectionInfo name] isEqualToString:@"DatasetA"]) {
    DatasetACell *datasetACell = [collectionView dequeueReusableCellWithReuseIdentifier:datasetACellIdentifer forIndexPath:indexPath];

    DatasetA *datasetA = [self.fetchedResultsController objectAtIndexPath:indexPath];
}

但我遇到了一个问题,它试图加载错误的数据集单元格。

这应该可行吗?我需要在其他地方寻找错误吗?还是我做错了这部分?

编辑:

我所拥有的应该可以工作。问题是索引没有对齐。

对于我的 fetchedResultsController,我将其创建为:

_fetchedResultsController = [Dataset MR_fetchAllSortedBy:NAME
                                               ascending:TRUE
                                           withPredicate:predicate
                                                 groupBy:@"datasetType"
                                                delegate:self.fetchedResultsController.delegate
                                               inContext:[NSManagedObjectContext MR_contextForCurrentThread]];

这会获取它们并按名称对其进行排序。我在项目中使用了 Magical Record,并且我使用了它的 fetch 控制器,因为我无法让 Core Data fetch 控制器工作:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Dataset" inManagedObjectContext:[NSManagedObjectContext MR_contextForCurrentThread]];

[fetchRequest setEntity:entity];

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:NAME ascending:TRUE selector:@selector(caseInsensitiveCompare:)];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];

[fetchRequest setSortDescriptors:sortDescriptors];

NSError *error;

NSArray *fetchedArray = [[NSManagedObjectContext MR_contextForCurrentThread] executeFetchRequest:fetchRequest error:&error];
NSLog(@"fetchedArray: %@", fetchedArray);

NSFetchedResultsController *FRC = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[NSManagedObjectContext MR_contextForCurrentThread] sectionNameKeyPath:nil cacheName:nil];
FRC.delegate = self;

我在这段代码中执行的 fetchRequest 返回实体,一旦我将它通过 fetch 控制器,它总是什么都不返回。我不认为它喜欢 MR 的上下文。 /难以置信

当我尝试填充每个子类UICollectionViewCell(DatasetACell、DataseetBCell 等)时,它可能会检索到错误的数据单元格。

所以在 indexPath (0,0) 处,NSFetchedResultsController

[self.fetchedResultsController sections] objectAtIndex:indexPath]

将返回一个datasetA实体,而collection view为同一个索引

[collectionView dequeueReusableCellWithReuseIdentifier:datasetACell forIndexPath:indexPath] 

返回一个datasetBCell。

NSFetchedResultsController 已排序而 [collectionView dequeueResuableCellwithReuseIdentifier:forIndexPath] 未排序存在问题。

完整代码:

-(NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"boundary.boundaryID == %@", self.dataseter.boundaryID];

    _fetchedResultsController = [Dataset MR_fetchAllSortedBy:NAME
                                                   ascending:TRUE
                                               withPredicate:predicate
                                                     groupBy:@"datasetType"
                                                    delegate:_fetchedResultsController.delegate
                                                   inContext:[NSManagedObjectContext MR_contextForCurrentThread]];

    return _fetchedResultsController;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    id sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:indexPath.section];
    NSLog(@"indexPath: %@", indexPath);
    NSLog(@"[sectionInfo name]: %@", [sectionInfo name]);


    if ([[sectionInfo name] isEqualToString:SAVED_ANALYSIS]) {
        NSLog(@"section name is DATASET A");

        DatasetCellA *datasetCellA = (DatasetCellA *)[collectionView dequeueReusableCellWithReuseIdentifier:datasetcellAIdentifier forIndexPath:indexPath];

        DatasetA *datasetA = [self.fetchedResultsController objectAtIndexPath:indexPath];
        NSLog(@"datasetA.id: %@", datasetA.id);
        NSLog(@"datasetA: %@", datasetA);

        // configure and return cell
    }
    else if ([[sectionInfo name] isEqualToString:EDITED_IMAGES]) {
        NSLog(@"section name is DATASET B");

        DatasetCellB *datasetCellB = (DatasetCellB *)[collectionView dequeueReusableCellWithReuseIdentifier:datasetCellBIdentifer forIndexPath:indexPath];

        DatasetB *datasetB = [self.fetchedResultsController objectAtIndex:indexPath];
        NSLog(@"editedImage.id: %@", datasetB.id);
    NSLog(@"editedImage: %@", datasetB);

        // configure and return cell
    }
}

日志:

2013-04-04 10:59:38.697 [2380:14003] indexPath: <NSIndexPath 0x19b645c0> 2 indexes [0, 0]
2013-04-04 10:59:38.697 [2380:14003] [sectionInfo name]: Dataset B
2013-04-04 10:59:38.697 [2380:14003] section name is DATASET B
2013-04-04 10:59:38.702 [2380:14003] datasetB.id: 1581
2013-04-04 10:59:38.703 [2380:14003] datasetB: <DatasetA: 0x1c193ac0> (entity: DatasetA; id: 0x16141bd0 <x-coredata://9313C8D3-0AA8-4F3F-B32D-F1F7843D4FA1/DatasetA/p168> ; data: {

})
2013-04-04 10:59:38.703 [2380:14003] indexPath: <NSIndexPath 0x19b64560> 2 indexes [1, 0]
2013-04-04 10:59:38.703 [2380:14003] [sectionInfo name]: Dataset A
2013-04-04 10:59:38.704 [2380:14003] section name is DATSET A
2013-04-04 10:59:38.709 [2380:14003] datasetA.id: 75
2013-04-04 10:59:38.709 [2380:14003] datasetA: <DatasetB: 0x1c15a830> (entity: DatasetB; id: 0x16141b30 <x-coredata://9313C8D3-0AA8-4F3F-B32D-F1F7843D4FA1/DatasetB/p165> ; data: {

})
2013-04-04 10:59:38.724 [2380:14003] -[DatasetB mode]: unrecognized selector sent to instance 0x1c15a830
2013-04-04 10:59:38.725 [2380:14003] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[DatasetB mode]: unrecognized selector sent to instance 0x1c15a830'
*** First throw call stack:
(0x1c19012 0x1a3ee7e 0x1ca44bd 0x1c08bbc 0x1c0894e 0x80028 0xe862da 0xe878f4 0xe89b91 0x9d32dd 0x1a526b0 0x56cfc0 0x56133c 0x561150 0x4df0bc 0x4e0227 0x4e08e2 0x1be1afe 0x1be1a3d 0x1bbf7c2 0x1bbef44 0x1bbee1b 0x28cc7e3 0x28cc668 0x982ffc 0x1ebd 0x1de5)
libc++abi.dylib: terminate called throwing an exception

对于第一个索引(0,0),代码认为它是DatasetB,但实际上是DatasetA。在第二个索引 (1,0) 中相反;代码认为它是一个DatasetA,但它是一个DatasetB。在这个集合中,有 1 个 DatasetB 和许多 DatasetA。

当 fetch 控制器对其进行排序时,它首先对 Dataset B 进行排序。集合视图需要一个 DatasetB,但 fetch 控制器正在为同一索引返回一个 DatasetA。

【问题讨论】:

  • 您确定为不同的细胞类型设置了不同的重用标识符吗?你所拥有的应该几乎可以按原样工作。
  • 这是我检查的第一件事。
  • NAME 定义为什么?
  • NSString * const NAME = @"name";

标签: ios objective-c nsfetchedresultscontroller uicollectionview magicalrecord


【解决方案1】:

看来排序有问题,需要排序。

但我的问题是你为什么要打开部分名称?为什么不直接打开项目的类?

id object = [self.fetchedResultsController objectAtIndexPath:indexPath];

if ([object isKindOfClass:[DatasetA class]] {
  // Do your DatasetCellA stuff
} else if ([object isKindOfClass:[DatasetB class]) {
  // Do your DatasetCellB stuff
}

至少这样你不会有排序问题

您可能想要更正您的获取请求,以便按datasetType 排序,然后按name

- (NSFetchedResultsController *)fetchedResultsController
{
  if (!_fetchedResultsController) {
    return _fetchedResultsController;
  }

  NSFetchRequest *request = [[NSFetchRequest alloc] init];
  request.entity          = [Dataset MR_entityDescription];
  request.sortDescriptors = @[
                            [NSSortDescriptor sortDescriptorWithKey:@"datasetType" ascending:YES],
                            [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:NO],
                            ];

  _fetchedResultsController = 
    [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                        managedObjectContext:[NSManagedObjectContext MR_context]
                                          sectionNameKeyPath:@"datasetType"
                                                   cacheName:nil];

  NSError *error = nil;
  if (![_fetchedResultsController performFetch:&error]) {
    NSLog(@"Could not perform fetch %@", [error localizedDescription]);
  }

  _fetchedResultsController.delegate = <..your delegate..>;

  return _fetchedResultsController;
}

另外,你自己创建的fetchResultsController 可能什么也没返回的原因是因为你自己没有使用 fetch 请求执行 fetch,而是通过 fetchedResultsController 来完成

if ([fetchedResultsController performFetch:&error]) {
   //...

【讨论】:

  • 好的,这可以防止它崩溃。它将使用正确的单元格,但我仍然在 DataseB 部分中使用 DatasetA 单元格。我正在寻找如果 indexPath.section 是 DatasetA,则获取 DatasetA 实体和单元格并放置在该部分中。问题出在 indexPath 上,我没有从获取的控制器中获得正确的数据集实体。
  • 做到了!非常感谢!我最初尝试为此使用苹果 NSFetchedResultController 方式,但我无法让它工作(Magical Record 方法只是一个包装器,他们说他们不会做任何超越)。 FRC 修复适用于或不使用您建议的开关更改。
  • 如果您查看神奇记录助手的来源,您会发现他们为您调用 performFetch: - 这就是您之前所缺少的
【解决方案2】:

如果没有更多关于模型结构的知识,我无法确定,但是这里......

我认为您的问题是您希望搜索结果以某种方式排序,但它们并没有按照您期望的方式排序。

数据集使用groupBy:@"datasetType" 子句,它定义了各个部分。但是这些部分也将通过 groupBy 键隐式排序。所以问题是:

您的模型中的这个datasetType 键是什么,它是您所期望的吗?显然您想按数据集名称排序,但 datasetType 是什么名称?这就是我认为问题所在。您正在检索错误的排序顺序,因为您没有按数据集的名称进行分组。

PS:您有“DATSET A”和“DATASET B”...因此,如果您确实按数据集名称进行分组,那么一切都按预期工作...除了您的名称有错别字。

【讨论】:

  • datasetType 是一个具有“datasetA”或“datasetB”值的 NSString 值。因此,在每个部分中,都是数据集A 或所有数据集B。分组的我相信NSFetchedResultsController init 方法中的sectionNameKeyPath: 参数是等价的。所以它们应该按 datasetType 分组并按名称排序。我确实注意到这些部分也按名称排序。
  • 所以这些部分按您希望的方式按名称排序。
  • 错字没有任何影响。它只是记录,嘿,我输入了 If stmt for when if ([[sectionInfo name] isEqualToString:SAVED_ANALYSIS])
  • 是的,这些部分按名称排序。实体也按名称排序。
【解决方案3】:

您的数据集名称显然有错字:

2013-04-04 10:59:38.704 [2380:14003] section name is DATSET A

由于 DATSET A 中缺少第二个“A”,这将排在 DATASET B 之后。

文字的危害。

【讨论】:

  • 这只是我重命名事物的一种方式。如果你看代码,那只是一个 NSLog 说它进入了 DATASETA if stmt.
  • 好的,但是如果 SAVED_ANALYSIS 有相同的错字(复制和粘贴?),它会产生这种效果。由于未发布定义 SAVED_ANALYSIS 的代码,因此很难检查,并且在两个不同位置必须匹配的文字,这是一个常见问题。 :-)
  • 应该记录代码NSLog(@"section name is DATASET A");。我重命名了我的对象以使其在概念上更易于理解,并且当我重命名日志时,我输入了 DATSETA 而不是 DATASETA。除此之外,如果你的意思是datasetA: &lt;DatasetB: 0x1c15a830&gt;; “datasetA”是应该存在的,而 是实际加载的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多