2013-02-09 3 views
3

создать новые вкладки проекта в Xcode, в AppDelegate я создал протоколObjective-C делегатов многоадресной

.h файл

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

.m файл

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

В firstViewController & secondViewController (оба отображаются как две разные вкладки) Я сделал это как в

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

Код работает отлично, но отвечает только secondViewController.

Я ищу механизм вещания и слушателя, используя делегаты, не являющиеся уведомлениями.

Я искал много, но нашел какие-либо решения, кроме this, но код для меня понятен, поэтому я делаю шаг за шагом, чтобы понять это, начиная с простого проекта. Пожалуйста, помогите мне в этом. Как оба диспетчера разрешений могут одновременно отвечать делегату, что мне делать?

+0

Может быть делегатом только один объект (за один раз), поэтому он не работает. Какими уведомления являются механизмы вещания и прослушивания. Почему бы вам не использовать это? – rdelmar

+0

Уведомление @rdelmar не возвращает значений, и для полной информации, пожалуйста, перейдите по ссылке, которую я предоставил. Сначала я тоже думал, почему не уведомление, но после работы над xmppframework я получил ответ. –

+0

Почему бы не создать массив объектов-делегатов? – overboming

ответ

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 имеет сильные ссылки. Здесь вы можете найти хорошее решение для этого:

NSArray of weak references (__unsafe_unretained) to objects under ARC

Это в основном говорит использовать NSValue для хранения слабых ссылок с помощью метода valueWithNonretainedObject.

+0

моя точка смятения - как она будет работать, в appDelegates - как [mypDelegate myProtocolMethodOne]; означает, что кто-либо когда-либо реализует протокол, должен реагировать так, чтобы отвечал только один. Пожалуйста, помогите мне в этом. –

+0

Я добавил эту часть в раздел «Как вызвать методы делегатов». –

+0

если я повторяю его как [objectAtIndex0InArray myProtocolMethodOne]? –

5

Вместо делегатов вы можете рассмотреть что-то похожее на шаблон посетителя.

@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 
5

Поскольку делегат является простой переменной, присваивание ему заменяет значение, а не добавляет к нему.Вы можете преобразовать его в массив, но поскольку NSArray сохраняет сильные ссылки на объекты внутри него, вам нужно иметь дело с потенциальными круговыми ссылками. (Круговая ссылка в этом случае состоит в том, что два объекта принадлежат друг другу. Поскольку они оба принадлежат кому-то, ни один из них не будет освобожден. Хотя они только принадлежат друг другу. Wikipedia has more. Но типичный шаблон в Objective-C состоит в том, чтобы сделать все делегаты слабы по этой причине.)

Вместо делегатов вы можете рассмотреть возможность использования уведомлений NSNotificationCenter.

Вместо 1: 1 они 1: любые (включая 0 без особых соображений). Идея в том, что один объект сообщений уведомление, а также интересующие его объекты наблюдать it. Каждый объект может выбрать, какие события они заинтересованы в

Там несколько шагов, которые вам необходимо выполнить:.

  1. Удалить весь код делегата вы написали.
  2. Согласовать название уведомления.
  3. Зарегистрируйте объекты, которые будут отвечать на уведомление. (Здесь вы устанавливаете делегата.)
  4. Обращайтесь с уведомлением.
  5. Опубликовать уведомление (где ранее вы называли делегата).
  6. Отменить регистрацию объектов при их уничтожении.

Что бы вы сделали, это согласовать ключ, возможно, в константе.

Keys.h:

extern NSString *MethodOneNotification; 

Keys.m:

NSString *MethodOneNotification = @"MethodOneNotification"; 

Затем зарегистрироваться в firstViewController и secondViewController как этот где-то вроде viewDidLoad:

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

Предоставлять обработчик в обоих firstViewController и secondViewController для селектора:

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

вызова уведомление, где вы раньше называли делегат:

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

И в обоих firstViewController и secondViewController, вы хотите, чтобы удалить регистрацию уведомлений (конечно, в 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: с массивом. Но, по крайней мере, вы пропустили круговые ссылки.

Другой способ решить это с помощью блоков. Тем не менее, это удвоит размер этого ответа. :) Итог, однако: шаблон делегата является неправильным шаблоном для этой проблемы. К счастью, другие легко подобрать.

+0

Спасибо, что ответили, пожалуйста, скажите мне, что делать, если мне также нужно вернуть значения. –

+0

Обновленный ответ одним способом. –

+0

(Btw, спасибо за интересный вопрос.) –

Смежные вопросы