0

ObjectAを作成するViewControllerがあります。次に、ObjectAはObjectBを作成します。ObjectBは、View Controllerからいくつかの値を取得する必要があります(オブジェクトの作成後に変更できる値が必要です)。

値を取得するための最良の方法を見つけようとしています。私が最初に考えたのはプロトコルです。これまで、オブジェクト内にプロトコルを作成しただけです。

#import <UIKit/UIKit.h>

@protocol AnalysisTypeTableDelegate;

@interface AnalysisTypeTableViewController : UITableViewController

@property (weak, nonatomic) id <AnalysisTypeTableDelegate> delegate;

@property (strong, nonatomic) NSArray *dataSource;

@property (nonatomic) BOOL allowRefresh;

@end

@protocol AnalysisTypeTableDelegate <NSObject>

-(void)returnAnalysisType:(NSString *)type;

@end

プロトコルクラスを作成するにはどうすればよいですか(新しいファイルの作成、Objective-Cプロトコルなど)?

では、どうすればそれらをリンクできますか?ObjectAにはプロトコルがありますが、次のようなことをしますか?

// View controller and objectB both conform to myProtocol

// view controller creates objectA
myObjectA.delegate = self

// when objectA creates objectB
myObjectB.delegate = self.delegate

または、必要な値を取得するためのより良い方法はありますか?

編集:

私はこのようなことをする必要があると思います:

objectAのプロトコル:

@protocol objectADelegate

-(NSDictionary)requestViewController;

@end

objectBのプロトコル:

@protocol objectBDelegate

-(NSDictionary *)requestObjectA;

-(void)updateList:(NSSarray *)list;

@end

myObjectBで

-(NSDictionary *)requestObjectA {
    NSDictionary *extents = [self.delegate requestObjectA];
}

-(void)serverCall {
    // make server call, get list
    ...
    // update myObjectA with new list
    [self.delegate updateList:newList];

myObjectAで

-(NSDictionary *)requestObjectA {
    return [self.delegate requestViewController];
}

-(void)updateList:(NSArray)list {
    // updates list
}

ビューコントローラで

-(NSDictionary *)requestViewController;
    return self.mapkit.exents;
}
4

1 に答える 1

1

これはView Controllerから呼び出されると言っていると思います:

myObjectA.delegate = self

そして、オブジェクト A から次の行を呼び出していることに注意してください。

myObjectB.delegate = self.delegate

技術的には、それを行うことができますが、その構成は少しわかりにくいと思います。delegateビューコントローラーが「わかりました、もうなりたくない」と言うメカニズムを提供していないため、少し問題がありますmyObjectA。おそらくView Controllerはの存在さえ知らないため、View Controllerがそれ以上にmyObjectBなりたくないことを伝えるメカニズムはありません。delegateB


Model-View-Controller パターンを使用する

の概念はdelegate、「自分のことを伝えたいdelegate、またはそれを要求したい」ということの 1 つです。一方、あなたの目標がそれらの間でデータを共有することである場合、デリゲート プロトコル パターンからモデル ビュー コントローラー(MVC) パターンに移行する傾向があります。 「モデル」部分:

  • Modelモデル データを保持するクラスを作成します。

  • ビュー コントローラーでModelクラス オブジェクトをインスタンス化します。

  • オブジェクトへのポインターを、Modelあるビュー コントローラーまたはオブジェクトから次のオブジェクトに渡します (または、シングルトン パターンやアプリ デリゲート プロパティなどを介して、このモデル オブジェクトを他のクラスからアクセスできるようにします)。

  • クラスに、維持されているデータに関連付けられたプロパティがあることを確認してくださいModel(そうすれば、他のクラスは、Model合成するアクセサ メソッドを使用できます)。

これは概念的にはdelegateポインターで概説したものと非常に似ていますがdelegate、データにアクセスするだけでなく、コントローラーに何かをするように指示できるという意味はありません。デリゲート プロトコル パターンでは、デリゲートは通常、delegateいつでも a であることをオプトアウトできる必要があります。


モデル データの変更を処理するためのさまざまなアプローチ

モデル オブジェクトへの変更を他のオブジェクトに反映するには、いくつかの方法があります (たとえば、モデル データが変更され、その変更を反映する必要があることをビュー コントローラーに伝えるなど)。これらには以下が含まれます:

  1. デリゲートを使用します。モデル データの変更について複数のオブジェクトに伝えたい場合は、複数のデリゲート (またはそれらの配列) が必要になるため、これはおそらくここに挙げるアプローチの中で最悪の方法です。これはデリゲートの不適切な使用です。

  2. でリロードしますviewDidAppear。ビュー コントローラーがビューを更新して、別のビュー コントローラーで変更されたデータを反映するようにするだけの場合は、ビューが再び表示されたときにビューを更新するだけです。これは最も原始的なソリューションであり、たとえば、データを変更したモーダル ビューが破棄された後に再表示されるビュー コントローラーを扱っている場合にのみ機能します。これらの単純なケースでは、これが最も簡単な解決策であることがよくあります。

    - (void)viewWillAppear:(BOOL)animated
    {
        [super viewWillAppear:animated];
    
        [self updateField1Label];
        [self updateField2Label];
        [self.tableView reloadData];
    }
    
  3. を通じて通知に登録しNSNotificationCenterます。これには、複数のオブジェクトが自分自身をオブザーバーとして同じ通知に追加できるという利点があります。たとえば、.m ファイルで通知のキーを定義します。

    NSString * const kNotificationField1Changed = @"com.log139.field1";
    

    次に、.h ファイルでそのキーへの外部参照を定義します。

    extern NSString * const kNotificationField1Changed;
    

    次に、変更の通知を希望するオブジェクトをその通知に登録できます。

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleField1Notification:)
                                                 name:kNotificationField1Changed
                                               object:nil];
    

    明らかに、その「ハンドラー」メソッドを作成する必要があります。

    - (void)handleField1Notification:(NSNotification*)notification
    {
        self.field1Label.text = self.model.name;
    }
    

    最後に、そのモデル フィールドが通知を投稿できる更新はすべて、次のようになります。

    - (void)saveAndPop:(UITextField *)textField
    {
        self.model.field1 = textField.text;
    
        [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationField1Changed
                                                            object:self
                                                          userInfo:nil];
    
        [self.navigationController popViewControllerAnimated:YES];
    }
    

    これを行う場合は、通知用に登録したオブジェクトが範囲外になったときに、その通知用に登録解除する必要があることを確認する必要があります。

    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:kNotificationField1Changed
                                                  object:nil];
    
  4. キー値監視を使用します。繰り返しますが、複数のオブジェクトを登録して、モデルのプロパティのオブザーバーにすることができます。オブジェクトに3 つのプロパティを ( 経由で@property)定義したとしModelます。変更の通知を希望するオブジェクトは、これらのプロパティのオブザーバーとして自分自身を追加できます。次に例を示します。

    [self.model addObserver:self forKeyPath:@"field1" options:0 context:NULL];
    [self.model addObserver:self forKeyPath:@"field2" options:0 context:NULL];
    [self.model addObserver:self forKeyPath:@"field3" options:0 context:NULL];
    

    observeValueForKeyPathあとはメソッドを書くだけです:

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        if ([keyPath isEqualToString:@"field1"])
            [self updateField1Label];
    
        else if ([keyPath isEqualToString:@"field2"])
            [self updateField2Label];
    
        else if ([keyPath isEqualToString:@"field3"])
            [self.field3TableView reloadData];
    }
    

    ここで注意が必要なのは、オブジェクトの 1 つがコレクション (たとえば a ) の場合、コレクション アクセサーNSMutableArrayを記述する必要があることだけです。その他の例については、そのドキュメントを参照してください。たとえば、ペットの名前の配列であるプロパティを持つモデルがあります。したがって、モデル用に次の 2 つのメソッドを作成する必要がありました。NSMutableArray *petNames

    - (void)insertObject:(NSString *)petName inPetNamesAtIndex:(NSUInteger)index
    {
        [self.petNames insertObject:petName atIndex:index];
    }
    
    - (void)removeObjectFromPetNamesAtIndex:(NSUInteger)index
    {
        [self.petNames removeObjectAtIndex:index];
    }
    

    を呼び出す代わりに、代わりに呼び出し[self.model.petNames addObject:aPetName]まし[self.model insertObject:aPetName inPetNamesAtIndex:0];た (そうすることで、通知が自動的に行われます)。

要するに、モデルデータの変更を通知する必要があるオブジェクトが複数ある場合は、キー値を監視するのが最もエレガントなアプローチだと思いますが、対処する場合は腕をつかむのに少し時間がかかりますコレクション。通知を投稿するだけでも比較的簡単な代替手段だと思います。


参考文献:

于 2013-02-14T15:46:29.613 に答える