4

コレクション ビューを含む標準のビュー コントローラーがあります。

のカスタム サブクラスから作成されたカスタム セルをコレクション ビューに入力していますUICollectionViewCell

  1. コレクション ビュー セル クラス内からコレクション ビュー クラスのメソッドを呼び出すベスト プラクティスは何ですか

  2. コレクション ビュー セル クラスで次の init が呼び出されないのはなぜですか。collectionView クラスがセルを作成するときに呼び出されると思いました。

    (id)initWithFrame:(CGRect)frame

これを行う理由は、コレクション ビュー セルを削除しているためです。削除関数はコレクション ビュー セル クラス内にあります。削除時にサウンドを再生したいのですが、セルごとではなく、コレクションビューコントローラークラスでサウンドを初期化します。

4

2 に答える 2

12

セルから CollectionView への後方参照を iVar またはプロパティとして追加しないでください。これは、本当に (本当に) 不適切な相互参照 (objA が objB を指し、objB が objA を指す) になるためです。コンパイル エラー (@classステートメントでひどく修正される可能性があります) などの小さな問題に加えて、これにより、割り当て解除できないオブジェクト、メモリ リーク、ゾンビなどの重大な問題が発生します。

経験則は次のとおりです。

親は子供のことを知っていますが、子供は親のことを知ってはいけません。

言い換えれば、CollectionView はそのセルを認識していますが、セルは CollectionView を認識するべきではありません。

可能な解決策

  1. タスクとソリューションを再設計します。セルではなく、collectionView にタップ ジェスチャ レコグナイザーを追加することもできます。選択したセルを提供する -indexPathForItemAtPoint: があります。

  2. 逆参照が絶対に必要な場合:プロトコルを定義し、デリゲートを使用します。Cocoa / Cocoa Touchでよくあるデザインパターンです。デリゲートの設計パターンについて読む必要がありますが、要するに、これがその方法です。


セルでプロトコルを定義します (このプロトコルを定義することにより、セルは親のタイプを認識していないことを思い出してください。「親」で使用可能なメソッドが 1 つ以上あることを認識しているだけです)。

// 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 への参照がありません。したがって、セルからコレクション ビューに通信する場合は、セルにプロパティまたは ivar を追加する必要があります。

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

第 2 に、nib から UICollectionViewCell をインスタンス化する場合、initWithFrame: は呼び出されません。代わりに initWithCoder: が呼び出されます。initWithCoder: をオーバーライドする (および super を呼び出す) か、-awakeFromNib を実装できます。

1 つのクラスに 2 つの init メソッド ( initWithFrame: と initWithCoder: など) を実装する必要がある場合に私が行うことは、それぞれの実装で commonInit という 1 つのメソッドを呼び出すことです。

- (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 に答える