UICollectionCell在CollectionViewController中调用方法

Dog*_*fee 4 ios uicollectionviewcell

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

我正在使用从自定义子类创建的自定义单元格填充集合视图UICollectionViewCell.

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

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

    (id)initWithFrame:(CGRect)frame

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

auc*_*uco 12

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

经验法则是:

父母知道他们的孩子,但孩子一定不了解他们的父母.

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

可能的解决方案

  1. 重新设计您的任务和解决方案.也许在collectionView上添加一个tap手势识别器,而不是在单元格上.有-indexPathForItemAtPoint:为您提供选定的单元格.

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


在单元格中定义协议(请记住,单元格不知道父类型,通过定义此协议,它只知道"父"上有一个或多个可用的方法)

// in cell.h
@protocol MyCellProtocol
- (IBAction)doSomething:(id)sender;
@end
Run Code Online (Sandbox Code Playgroud)

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

// in cell.h
@property (assign) id<MyCellProtocol> cellDelegate;
Run Code Online (Sandbox Code Playgroud)

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

// in cell.m, some method:
[self.cellDelegate doSomething:nil];
Run Code Online (Sandbox Code Playgroud)

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

// in collectionViewController.m
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                  cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = 
      [self.collectionView dequeueReusableCellWithReuseIdentifier:@"myCell" 
                                                     forIndexPath:indexPath];
    cell.cellDelegate = (id<MyCellProtocol>)self;
Run Code Online (Sandbox Code Playgroud)


bne*_*ely 5

默认情况下,UICollectionViewCell没有引用包含它的UICollectionView.因此,如果要从单元格与集合视图进行通信,则需要在单元格中添加属性或ivar.

cell = [UICollectionViewCell ...];
cell.collectionView = self.collectionView;
Run Code Online (Sandbox Code Playgroud)

其次,当从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
}
Run Code Online (Sandbox Code Playgroud)

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

参考:initWithFrame的UIView文档: