2

私はいくつかのパラメータを取る一般的なルーチンを持っています。何かのようなもの:

-(id) doStuff:(int)A:(int)B:(int)C {
    //doStuff
    return object;
}

私はUITableViewController、それぞれが独自の ID を持つ多数のカスタムセルを収容する を持っています。[保存] をクリックすると、これらのセルが繰り返され、一部のセルは保存時に「追加の動作」が必要になります。

これまでNSString *、カスタム セルにデリゲートを格納する「Callback」オブジェクトを作成しました。「保存」されると、セルは、適用して使用するコールバックがあるかどうかを調べます

SEL sel = NSSelectorFromString(Sel);
if([Del respondsToSelector:sel])
    [Del performSelector:sel withObject:Cell];

これである程度うまくいきます...ただし、渡されたセルのIDでスイッチ/ケースを実行するには、渡すメソッドが必要であり、それを避けたいと思います。

そのため、代わりにブロックを使用したいのですが、パラメーター化されたブロックを変数に格納する方法がよくわかりません。

私がやろうとしていること:

関数ブロックを宣言しますdoStuff

id (^doStuff) (int, int, int) = ^(int A, int B, int C) {
    //does Stuff
};

そして、以前に作成したブロックをコールバックとして追加します

[Cell addCallback:(^doStuff)(1, 2, 3)];

ブロックはその時点で呼び出されてはなりませんが、セルに保存され、適切なタイミングでのみ呼び出されます。どうすればこれを正しく行うことができますか?

どうもありがとうございました。

編集:私が避けたいのは、ブロックのパラメーターをセルに保存し、呼び出し時にそれらを渡すことです。これは、セルを不必要にさらに特殊化する必要があるためです。

4

3 に答える 3

1

あなたが望むのは、次のようなブロックを呼び出すブロックのようです。

[cell addCallback:^{ doStuff(1, 2, 3); }];

しかし、これはかなり奇妙で複雑なデザインです。おそらく1つのブロックだけでそれを書く方法があるように思えますが、あなたが何をしているのかについてのより良い考えなしに具体的な解決策を与えることは困難です.

于 2012-12-12T07:56:30.670 に答える
0

この回答は Chuck の提案に基づいており、それを実現するために遭遇した落とし穴について説明しています。

作成:

Cell = [self CreateCell];
[Cell addCallback:^{ return doStuff(Cell, 1, 2, 3, 4) } At:ON_SAVE];

doStuff は、セルの前に宣言されたローカル ブロックです。ブロック内の呼び出しセルへの参照も必要だったため、セルに直接追加することはできませんでした。

この時点での落とし穴: クラス変数。ブロックはローカル変数のみを保持します...または「コピー」します...ローカル変数は保持しますが、クラス変数は保持しません。'Cell' がクラス変数であり、'CreateCell' によって設定されると仮定すると、ブロックは、ブロックの実行時に Cell の値で機能します。

そのため、必要に応じてクラス変数の値を想定するローカル変数を宣言することを忘れないことが重要です。

保管所:

- (void) addCallback:(CallBlock_t)B At:(int)at {
    //Creates a Callback-Object and passes it the block and adds it to an Array.
}

- (id) initWithBlock:(CallBlock_t)B At:(int)at {
    self = [super init];
    if(self) {
        Block = [B copy];    //Yes, Copy. Not retain.
        When = at;
    }
    return self;
}

この時点での落とし穴: ブロックが単に保持されている場合、呼び出し元の関数からのローカル ブロックが範囲外になり、プログラムは「Bad Access」で失敗します。コピーはこの問題を解決します。

もちろん、(コールバック クラスの dealloc で) ブロックを使い終わったら、ブロックを解放する必要がありますが、それは当然のことです。

このちょっとした説明が誰かの悲しみを救ってくれることを願っています。

于 2012-12-12T09:58:51.867 に答える
0

最も簡単な方法は、ブロック パラメーターがどのように見えるかを含む typedef を作成し、それを使用して新しいプロパティ/ivar を宣言することです。次のサンプル コードは、Sensible TableViewフレームワークの SCCellActions クラスからコピーしたものです。

typedef void(^SCCellAction_Block)(SCTableViewCell *cell, NSIndexPath *indexPath);

@interface SCCellActions : NSObject
...
@property (nonatomic, copy) SCCellAction_Block willDisplay;
...
@end

その後、次のようにプロパティを設定できます。

cellActions.willDisplay = ^(SCTableViewCell *cell, NSIndexPath *indexPath)
{
    cell.backgroundColor = [UIColor yellowColor];
};

同様に、次のようにパラメーターを宣言できます。

...
- (void)callActionBlock:(SCCellAction_Block actionBlock)
{
    if(actionBlock)
    {
        actionBlock(self.cell, self.cellIndexPath);
    }
}
...

その場合、メソッドは次のように呼び出す必要があります。

[myObject callActionBlock:^(SCTableViewCell *cell, NSIndexPath *indexPath {cell.backgroundColor = [UIColor yellowColor];}];
于 2012-12-12T08:10:45.923 に答える