当我调用UICollectionViewCell dequeueReusableCellWithReuseIdentifier时,为什么要获取释放的内存调用?

时间:2013-02-06 01:45:45

标签: ios objective-c uicollectionview

我有一个包含自定义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测试,发现释放的内存调用来自此处。这是我第一次使用该仪器,所以我不确定如何从这里进行调查。

供参考,以下是代码中一些更相关的部分:

ViewController.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;
}

编辑:

如果我没有为tableview选择委托或数据源,则会加载带有tableviews的collectionview。将委托/数据源附加到文件所有者的某些操作导致错误。

1 个答案:

答案 0 :(得分:2)

当您注册UINib以进行单元重用时,dequeueReusableCellWithReuseIdentifier:forIndexPath:是在您注册的UINib上调用instantiateWithOwner:options:的内容。无论它通过所有者,是什么成为您的笔尖中的文件所有者插座。

看来你期望文件所有者成为UICollectionView,但我认为不是。

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

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

编辑:

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

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

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