0

Objective-C での委譲について理解を深めるために多くの時間を費やしました。ほとんどのケースで動作しましたが、特定のケースに問題があり、理解が困難です。私がやろうとしていることを説明しましょう:

GridLayoutViewのサブクラスであるというカスタム ビューがありUIViewます。SomeViewControllerのデリゲートであるView Controller もありGridLayoutViewます。

カスタムinitWithFrameメソッドがあり、条件付きで別の初期化メソッドを呼び出していますbaseInit。そのメソッドは、ある時点でデリゲート メソッドを呼び出します。からのコードは次のGridLayoutViewとおりです。

//
// Delegator
// GridLayoutView.m
//

@implementation GridLayoutView

- (id)initWithFrame:(CGRect)frame 
       numberOfRows:(NSUInteger)rows
       numberOfCols:(NSUInteger)cols
{
    self = [super initWithFrame:frame];
    if (self) {
        self.numberOfRows = rows;
        self.numberOfCols = cols;
        self.numberOfCells = rows * cols;

        if (self.numberOfCells > 0) [self baseInit];
    }
    return self;
}

- (void)baseInit
{
    // do some more initialization stuff here
    // ...

    // then call a delegate method
    [self.delegate someMethod:someObj];

    // However, this method is not called because self.delegate is nil
}

およびからのいくつかのコードSomeViewController:

//
// Delegate
// SomeViewController.m
//

@implementation SomeViewController

// ...

    // in some method
    self.gridLayoutView = [[GridLayoutView alloc] initWithFrame:gridLayoutFrame
                                                   numberOfRows:rowsCount
                                                   numberOfCols:colsCount];
    self.gridLayoutView.delegate = self;

// ...

デリゲート メソッドは 内baseInitで呼び出されることはありません。これは、デリゲートがnilその時点にあり、メソッドが完了した後に設定さinitWithFrameれるbaseInitためです。私はこれを確認しました。

委任のワークフローに何か問題があるように感じます。解決策はありますが、それが最善の方法だとは思いません。解決策は、基本的に、次のようなメソッドSomeViewControllerを変更して、インスタンスを委任者に渡すことです。initWithFrame

- (id)initWithFrame:(CGRect)frame 
       numberOfRows:(NSUInteger)rows
       numberOfCols:(NSUInteger)cols
           delegate:(id<GridLayoutViewDelegate>)aDelegate

このアプローチは機能しますがSomeViewControllerGridLayoutViewそのinitWithRect. これが委任を行う良い方法なのか、それともより良いアプローチがあるのか​​ 疑問に思っていますか? 誰かが私のためにこれをクリアできれば、とても感謝しています。

4

2 に答える 2

4

私の理解が正しければ、選択肢はあまりありません。

  1. デリゲートを渡すように(提案したように)イニシャライザを変更します。それは何も悪いことではありません、なぜあなたがそれを嫌いなのか分かりません。

  2. 初期化中にデリゲートへの依存関係を削除し、代わりに、setter をオーバーライドしてデリゲート プロパティが設定されたときに適切なデリゲート メッセージを送信します。


- (void)setDelegate:(id<GridLayoutViewDelegate>)aDelegate
{
    _delegate = aDelegate;
    // send whatever message makes sense to the delegate
    [_delegate someMethod:object];
}

編集 - あなたのコメントに気づきました

初期化メソッドにそれほど時間がかからないようにする必要があります。「ビューの読み込み」が何を意味するのかは不明です。単にサブビューを作成してビューに追加することを意味する場合、それは高速であり、進行状況をデリゲートに伝える必要はありません (初期化はメイン スレッド上にあり、UI は実行されません。すべての初期化が完了するまで更新します)。

長い時間がかかるデータの読み込みを意味する場合は、それを初期化から切り離し、バックグラウンド操作でデータを読み込み、進行状況メッセージをデリゲートに送信する必要があります。

于 2013-03-29T19:58:54.437 に答える
0

私は setDelegate 関数を実装してから [self someMethod:someObj]; を呼び出します。そこから

于 2013-03-29T20:02:33.673 に答える