1

我有一个包含自定义 UICollectionViewCells 的 UICollectionView(TestReceiptCell 是类名)。

当自定义单元格仅包含 UILabel 时,让 UICollectionView 出现并加载自定义单元格没有任何问题。

然后我通过 IB 将 UITableView 添加到 TestReceiptCell NIB 文件中。我在 TestReceiptCell.h 中为 UITableView 设置了一个引用出口,并在 .m 文件中合成。我将 UITableView 的委托和数据源设置为包含 UICollectionView 的 ViewController。

现在,当运行应用程序时,我在第三行的这个块中得到一个 EXC_BAD_ACCESS 异常:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *cellIdentifier = @"TestReceiptCell";
    TestReceiptCell *cell = (TestReceiptCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath]; //exception thrown here
    return cell;
}

我运行了 Zombie Instrument 测试,发现释放的内存调用源自这里。这是我第一次使用该仪器,所以我不确定如何从这里进行调查。

作为参考,这里有一些更相关的代码部分:

视图控制器.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self.myCollectionView registerNib:[UINib nibWithNibName:@"TestReceiptCell" bundle:nil]  forCellWithReuseIdentifier:@"TestReceiptCell"];

    // Setup flowlayout
    myCollectionViewFlowLayout = [[UICollectionViewFlowLayout alloc] init];
    [myCollectionViewFlowLayout setItemSize:CGSizeMake(310, 410)];
    [myCollectionViewFlowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
    [self.myCollectionView setCollectionViewLayout:myCollectionViewFlowLayout];
    self.myCollectionView.pagingEnabled = YES;
}

我也在 ViewController.m 文件中实现 UITableView 数据源和委托方法,但鉴于 EXC_BAD_ACCESS 异常的起源,我不确定问题是否出在此处:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 1;
}

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = nil;
    cell = [tableView dequeueReusableCellWithIdentifier:@"eventCell"];

    if(!cell){
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"eventCell"];
    }
    return cell;
}

更新:

如果我将 cellForItemAtIndexPath 更改为:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *cellIdentifier = @"TestReceiptCell";
    //TestReceiptCell *cell = (TestReceiptCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    TestReceiptCell *cell = [NSBundle.mainBundle loadNibNamed:@"TestReceiptCell" owner:self options:nil][0];
    return cell;
}

但是,我没有将单元格出列,并且知道这不是正确的方法。在 dequeueReusableCellWithResueIdentifier 创建新单元格时调用的 initWithFrame 方法中似乎存在问题。这是目前的方法:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"TestReceiptCell" owner:self options:nil];
        if ([arrayOfViews count] < 1) {
            return nil;
        }
        if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
            return nil;
        }
        self = [arrayOfViews objectAtIndex:0];
    }
    return self;
}

编辑:

如果我没有为表格视图选择委托或数据源,则将加载带有表格视图的集合视图。将委托/数据源附加到文件所有者的某些原因导致错误。

4

1 回答 1

2

当您注册一个 UINib 以进行单元重用时, dequeueReusableCellWithReuseIdentifier:forIndexPath: 就是在您注册的 UINib 上调用 instantiateWithOwner:options: 。无论它为所有者传递什么,都将成为您笔尖中的文件所有者出口。

看来您期望文件的所有者是 UICollectionView,但我不认为它是。

即使是这样,我认为您也不应该将 UICollectionView 用于每个集合单元格中包含的 UITableView 的委托。这将需要您的 UICollectionView 跟踪每个单元格中的 tableViews 和内容。

我建议将包含的 tableView 的委托设置为集合单元格本身,并让每个单元格管理自己的 tableview。

编辑:

您可以为您的集合视图单元定义一个委托协议,以将相关的表视图事件传递给集合视图。使用这种方法,您可以在集合视图数据源的 collectionView:cellForItemAtIndexPath 方法中为每个集合单元格设置委托属性。

例如,当用户从表格中选择一个项目时,您可以调用单元格委托来通知集合视图选择了哪个项目。

这种方法允许您抽象出您的集合单元格正在使用表格视图来显示单元格信息的事实。稍后,如果您决定使用例如嵌入式 UICollectionView 来显示这些项目,则委托协议可以保持不变,并且您可以隔离对集合单元格的更改。

于 2013-03-12T23:16:47.597 回答