3

xcodeで新しいタブ付きビュープロジェクトを作成し、appdelegateでプロトコルを作成しました

.hファイル

@protocol myProtocol <NSObject>
-(void)myProtocolMethodOne;
@end
.
.
.
@property (weak) id<myProtocol> mypDelegate;

.mファイル

@synthesize mypDelegate;
.
.
.
//Inside didFinishLaunchingWithOptions
[mypDelegate myProtocolMethodOne];

firstViewControllerとsecondViewController(両方とも2つの異なるタブとして表示されます)では、両方でこれを行いました

AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication]delegate];
    [ad setMypDelegate:self];
.
.
.
-(void)myProtocolMethodOne
{
    NSLog(@"1st VC");
    [[self tabBarItem]setBadgeValue:@"ok"];
}

コードは完全に機能していますが、secondViewControllerのみが応答しています。

通知ではなくデリゲートを使用するブロードキャストおよびリスナーのようなメカニズムを探しています。

たくさん検索しましたが、これ以外の解決策は見つかりましたが、コードは理解しやすいように進んでいるので、簡単なプロジェクトから始めて、段階的に理解していきます。これに関して私を助けてください。両方のビューコントローラが同時にデリゲートに応答するにはどうすればよいですか?どうすればよいですか?

4

3 に答える 3

5

デリゲートの代わりに、Visitorパターンのようなものを検討することもできます。

@interface MyVisitor : NSObject < myProtocol >

-(void)addAcceptor:(id < myProtocol >)acceptor

@end


@implementation

-(void)myProtocolMethodOne {
    [_acceptors enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *break){ 
        [obj performSelector:_sel];
    }];
}

// etc etc ... obviously you have to handle return values if you're getting these


@end
于 2013-02-09T06:09:18.080 に答える
5

デリゲートは単純な変数であるため、デリゲートに割り当てると、値が追加されるのではなく上書きされます。配列に変換することもできますが、NSArrayはその中のオブジェクトへの強力な参照を保持するため、潜在的な循環参照を処理する必要があります。(この場合の循環参照は、2つのオブジェクトがお互いを所有していることです。どちらも誰かが所有しているため、どちらも解放されません。お互いを所有しているだけですが、ウィキペディアにはもっとあります。しかし、Objective-Cの典型的なパターンはこの理由ですべての代表者を弱体化させるため。)

NSNotificationCenter代理人の代わりに、通知の使用を検討することをお勧めします。

1:1ではなく、1:anyです(特別な考慮なしに0を含む)。アイデアは、1つのオブジェクトが通知を投稿し、それに関心のあるオブジェクトがそれを監視するというものです。各オブジェクトは、関心のあるイベントを選択できます。

実行する必要のあるいくつかの手順があります。

  1. 作成したすべてのデリゲートコードを削除します。
  2. 通知名に同意します。
  3. 通知に応答するオブジェクトを登録します。(ここでデリゲートを設定します。)
  4. 通知を処理します。
  5. 通知を投稿します(以前に代理人に電話した場所)。
  6. オブジェクトが破棄されたら、オブジェクトの登録を解除します。

あなたがすることは、おそらく一定の鍵について合意することです。

Keys.h:

extern NSString *MethodOneNotification;

Keys.m:

NSString *MethodOneNotification = @"MethodOneNotification";

次に、登録してfirstViewControllersecondViewController次のような場所でこのようにしviewDidLoadます。

[[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(methodOneNotification:) object:nil];

firstViewControllersecondViewControllerセレクターの両方にハンドラーを提供します。

- (void)methodOneNotification:(NSNotification *)notification {
    NSLog(@"%@ got the notification!", [self class]);
}

以前に代理人に電話した場所で通知を呼び出します。

[[NSNotificationCenter defaultCenter] postNotificationName:MethodOneNotification
     object:nil];

そして、との両方firstViewControllersecondViewController、通知登録を削除する必要があります(確かにdeallocで):

- (void)dealloc {
    [[NSNotification defaultCenter] removeObserver:self name:MethodOneNotification
     object:nil];
    // [super dealloc] if you're not using ARC, but you should be
}

通知ハンドラー内で、通知の送信者にとしてアクセスできますnotification.object。通知とともに情報を渡す必要がある場合は、postNotification:を受け入れる別のバリ​​アントを使用できます。NSDictionaryその後、として辞書にアクセスできますnotification.userInfo

メッセージを投稿したオブジェクトに値を返す必要がある場合は、投稿者(としてアクセスできるnotification.object)にメッセージを送信して値を返送する必要があります。例えば:

- (void)methodOneNotification:(NSNotification *)notification {
    AppDelegate *appDelegate = notification.object;
    [appDelegate returningValue:1];
}

ここで、明らかに、AppDelegateはを定義して処理する必要があります-(void)returningValue:(int)value

クラスインスタンスの戻り値を保持する必要があります。もちろん、複数の返品が可能な場合は、それらをreturningValue:配列で収集する必要があります。しかし、少なくとも循環参照はスキップしました。

これを解決するもう1つの方法は、ブロックを使用することです。ただし、これはこの回答の2倍のサイズになります。:)しかし、結論:デリゲートパターンはこの問題の間違ったパターンです。幸いなことに、他のものは簡単に拾うことができます。

于 2013-02-09T23:20:50.963 に答える
4

あなたの場合、おそらくプライベートプロパティとしてデリゲートの配列を保持し、デリゲートを追加/削除できるようにすることで、すべてのデリゲートの配列を保持するのに十分です。

@interface AppDelegate() // .h file

@property (nonatomic,strong,readwrite) NSMutableArray* delegates;

@end 

// .m file

- (void) addDelegate: (id<MyProtocol>) delegate // By convention the first letter should be capital.
{
    // Optional code you may need to execute before adding it.
    [delegates addObject: delegate];
}

removeDelegateメソッドはお任せします。実装は非常に簡単です。

デリゲートメソッドを呼び出す方法

すべてのオブジェクトでセレクターを呼び出すだけで十分です。

[delegates makeObjectsPerformSelector: myProtocolMethodOne];

戻り値を取得する必要がある場合は、次のようにすることをお勧めします。

NSMutableArray* returnValues= [NSMutableArray new];
for(id<MyProtocol> delegate in delegates)
{
    id result= [delegate myProtocolMethodTwo]; // Method returning a value
    [returnValues addObject: result];
} 

デリゲートを追加する方法

すべてのコントローラー(最大N回)で、次のように追加できるはずです。

AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication]delegate];
[ad addDelegate:self];

追加の問題:弱いデリゲートが必要な場合がありますが、NSArrayは強い参照を保持します。ここでは、これに対する優れた解決策を見つけることができます:

ARC下のオブジェクトへの弱参照(__unsafe_unretained)のNSArray

基本的には、NSValueを使用して、valueWithNonretainedObjectメソッドを使用して弱参照を格納することを示しています。

于 2013-02-09T23:02:47.100 に答える