将一个委托方法多层次传递给navigationController堆栈

时间:2011-08-29 13:45:53

标签: objective-c ios delegates uinavigationcontroller

我在工具栏中有一个按钮,它有一个与之关联的弹出窗口。在popover中,我已经设置了一个navigationcontroller。我想要实现的是导航控制器堆栈中的两个或三个级别的视图控制器,以更改最初调用弹出窗口的按钮的状态。我设法做到了这一点,但它需要几个代表,看起来非常笨重;我在这里发帖的原因是要弄清楚是否有更优雅和有效的解决方案。

所以,开始吧:

//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,我的navController的rootViewController:

//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];

现在,这有效,但它似乎是一种Rube-Goldberg-ish方式。我尝试在MainController中初始化A_Controller和B_Controller并在那里将B_Controller的委托设置为MainController,然后使用两个viewcontrollers的NSArray来设置navcontroller堆栈,但它确实搞砸了viewcontrollers出现在navcontroller中的方式:I即使在navcontroller的rootviewcontroller上也会得到一个后退按钮,你可以继续单击Back并绕过navcontroller堆栈而不是停在根目录。有关更好方法的任何想法吗?

1 个答案:

答案 0 :(得分:1)

如果您想要分离视图控制器,您可以定义一个通知,然后发布该通知。

这样,只有接收通知的根视图控制器才需要知道深层嵌套视图控制器。

像这样定义通知:

// 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.
}