Передать метод делегата на нескольких уровнях вверх по стеку navigationController - PullRequest
1 голос
/ 29 августа 2011

У меня есть кнопка на панели инструментов, с которой связан поповер. В поповере я настроил навигационный контроллер. Я пытаюсь добиться того, чтобы контроллер представления был на два или три уровня ниже в стеке навигационного контроллера, чтобы изменить состояние кнопки, которая первоначально называлась поповер. Мне удалось это сделать, но для этого требуется пара делегатов, и это кажется очень неуклюжим; моя причина публикации здесь - выяснить, есть ли более элегантное и эффективное решение.

Итак, для начала:

//ProtocolDeclaration.h
@protocol ADelegate <NSObject>
- (void)changeButtonState;
@end

@protocol BDelegate <NSObject>
- (void)passTheBuckUpTheNavChain;
@end

Тогда для моего MainController, который удерживает кнопку:

// MainController.h
#import "A_TableController.h"
#import "ProtocolDeclaration.h"
@class A_TableController;
@interface MainController : UIViewController <ADelegate>
...
@end

// MainController.m
- (IBAction)buttonPressed:(id)sender {
    A_Controller *ac = [[[A_Controller alloc] init] autorelease];
    ac.ADelegate = self;
    UINavigationController *nc = [[[UINavigationController alloc] initWithRootViewController:ac] autorelease];
    UIPopoverController *pc = [[[UIPopoverController alloc] initWithContentViewController:nc] autorelease];
    [pc presentPopoverFromBarButtonItem...]
}

// ADelegate Method in MainController.m
- (void)changeButtonState
{
    self.button.style = ....
}

Теперь для A_Controller мой rootViewController для моего navController:

//A_Controller.h
#import "B_Controller.h"
#import "ProtocolDeclaration.h"
@class B_Controller;
@interface A_Controller : UITableViewController <BDelegate>
{
    id<ADelegate> delegate;
    ...
}
@property (assign) id<ADelegate> delegate;
...
@end

//A_Controller.m
//In the method that pushes B_Controller onto the stack:
B_Controller *bc = [[[B_Controller alloc] init] autorelease];
bc.BDelegate = self;
[self.navigationController pushViewController:bc animated:YES];

//In the BDelegate Method in A_Controller:
- (void)passTheBuckUpTheNavChain
{
    [ADelegate changeButtonState];
}

Наконец, в B_Controller:

//B_Controller.h
#import "ProtocolDeclaration.h"
@interface A_Controller : UITableViewController
{
    id<BDelegate> delegate;
    ...
}
@property (assign) id<BDelegate> delegate;
...
@end

//B_Controller.m
//Where it's necessary to change the button state back up in MainController:
[BDelegate passTheBuckUpTheNavChain];

Так вот, это работает, но это похоже на своего рода способ Рубе-Голдберга. Я попытался инициализировать оба A_Controller и B_Controller в MainController и установить делегат B_Controller на MainController прямо там, а затем использовать NSArray двух контроллеров представления для установки стека navcontroller, но он действительно испортил способ отображения контроллеров представления в контроллере navcon: Я получил бы кнопку «Назад» даже на корневом контроллере navcontroller, и вы могли бы просто продолжать нажимать кнопку «Назад» и вращаться вокруг стека navcontroller вместо того, чтобы останавливаться в корне. Есть идеи, как лучше это сделать?

1 Ответ

1 голос
/ 29 августа 2011

Если вы хотите отделить контроллеры представления, вы можете определить уведомление и просто опубликовать его.

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

Определите уведомление следующим образом:

// In .h
extern NSString* const BlaControllerDidUpdateNotification;

// In .m
NSString* const BlaControllerDidUpdateNotification = @"BlaControllerDidUpdateNotification";

Глубоко вложенный контроллер (BlaController) необходимо отправить сообщение следующим образом:

[[NSNotificationCenter defaultCenter]
        postNotificationName:BlaControllerDidUpdateNotification
                      object:self];

И контроллер корневого представления должен действовать на это как-то так:

// In init or the like:
[[NSNotificationCenter defaultCender] 
        addObserver:self
           selector:@selector(blaControllerDidUpdateNotification:)
               name:BlaControllerDidUpdateNotification
             object:nil];

// And then define this method:
-(void)blaControllerDidUpdateNotification:(NSNotification*)notification {
   // Update UI or whatever here.
}
...