4

我有一个包含集合视图的标准视图控制器。

我正在使用从UICollectionViewCell.

  1. 从集合视图单元类中调用集合视图类中的方法的最佳实践是什么

  2. 为什么在我的集合视图单元格类中没有调用以下init,我认为当collectionView 类创建我的单元格时会调用它。

    (id)initWithFrame:(CGRect)frame

我想这样做的原因是因为我正在删除一个集合视图单元格,删除函数在集合视图单元格类中。我想在删除时播放声音,并且宁愿在集合视图控制器类中初始化声音,而不是针对每个单元格。

4

2 回答 2

12

您真的不应该将单元格的反向引用作为 iVar 或属性添加到 CollectionView,因为您最终会得到一个非常(非常)糟糕的交叉引用(objA 指向 objB,objB 指向 objA)。除了像编译错误这样的小问题(可以用@class语句来修复),这也会导致严重的问题,比如不可释放的对象、内存泄漏、僵尸等等。

经验法则是:

父母知道他们的孩子,但孩子一定不知道他们的父母。

换句话说:CollectionView 知道它的单元格,但单元格不应该知道它们的 CollectionView。

可能的解决方案

  1. 重新设计您的任务和解决方案。也许在 collectionView 而不是在单元格上添加一个点击手势识别器。有 -indexPathForItemAtPoint: 给你选择的单元格。

  2. 如果您绝对需要反向引用:定义协议并使用委托。这是 Cocoa / Cocoa Touch 中常见的设计模式。您应该阅读委托设计模式,但简而言之,您就是这样做的:


在你的单元格中定义协议(记住,单元格不知道父节点的类型,通过定义这个协议,它只知道“父节点”上有一个或多个方法可用)

// in cell.h
@protocol MyCellProtocol
- (IBAction)doSomething:(id)sender;
@end

添加一个 id 类型的委托(这意味着,它可以是任何对象,只要它符合协议即可。换句话说:这将是您的 collectionView,但您不需要引用它!

// in cell.h
@property (assign) id<MyCellProtocol> cellDelegate;

现在您可以在您的单元格中调用委托:

// in cell.m, some method:
[self.cellDelegate doSomething:nil];

最后,您需要设置委托。在 UICollectionViewController 中创建/设置单元格时,将控制器设置为委托:

// in collectionViewController.m
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = 
      [self.collectionView dequeueReusableCellWithReuseIdentifier:@"myCell" 
                                                     forIndexPath:indexPath];
    cell.cellDelegate = (id<MyCellProtocol>)self;
于 2013-10-04T14:35:01.533 回答
5

默认情况下,UICollectionViewCell 没有引用包含它的 UICollectionView。所以如果你想从cell到collection view进行通信,你需要在cell中添加一个property或者ivar。

cell = [UICollectionViewCell ...];
cell.collectionView = self.collectionView;

其次,从 nib 实例化 UICollectionViewCell 时,不调用 initWithFrame:;initWithCoder: 被调用。您可以覆盖 initWithCoder:(并调用 super),或实现 -awakeFromNib。

有时,如果我必须在一个类中实现两个 init 方法(例如 initWithFrame: 和 initWithCoder: ),我会为每个实现调用一个名为 commonInit 的方法

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self commonInit];
    } 
    return self;
}

- (id)initWithCoder:(NSCoder *)encoder
{
    self = [super initWithCoder:encoder];
    if (self) {
        [self commonInit];
    } 
    return self;
}

- (void)commonInit
{
// set up your instance
}

这消除了代码重复并提供了一致的行为。

参考:initWithFrame 的 UIView 文档:

于 2013-09-16T08:40:24.470 回答