UINavigationBar topItem/items似乎是双弹出的

Dan*_*ace 5 cocoa-touch objective-c uinavigationbar uikit

我正在管理自己的UINavigationBar.由于皮肤粗糙,我需要这样做.UINavigationController的文档警告说,当与UINavigationController一起使用时,对UINavigationBar进行外观设置存在限制.

我已经进行了大量的日志记录,从我能说的一切,推动UINavigationController中的"后退"按钮弹出两个项目而不是一个.我得到一个委托回调告诉我它正在删除逻辑项,但它实际上删除了那一个.

应该永远不会删除添加到awakeFromNib中的UINavigationController的项目.它由于某种原因被删除.

有两个相似的问题,但都没有令人满意的答案.这两个问题是:

UINavigationBar .items访问器不返回当前的UINavigationItem

UINavigationBar似乎在"背面"弹出2个项目

- (void)awakeFromNib {
    [headerView setDelegate: self];
    [headerView pushNavigationItem: tableDisplay animated: NO];
}

- (void) selectedStory: (NSNotification *)not {
    [headerView pushNavigationItem: base animated: NO];
    NSLog(@"Selected story: %@", base);
}

- (void) baseNav {
    NSLog(@"Current items: %@", [headerView items]);
    BaseInnerItem *current = (BaseInnerItem *)[headerView topItem];
    [self addSubview: [current view]];
}

- (BOOL)navigationBar: (UINavigationBar *)navigationBar shouldPushItem: (UINavigationItem *)item {
    return YES;
}

- (BOOL)navigationBar: (UINavigationBar *)navigationBar shouldPopItem: (UINavigationItem *)item {
    return YES;
}

- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item {
    NSLog(@"didPushItem: %@", item);
    [self baseNav];
}

- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item {
    NSLog(@"didPopItem: %@", item);
    [self baseNav];
}
Run Code Online (Sandbox Code Playgroud)

编辑以从单次运行添加相关调试:

2010-10-13 02:12:45.911 Remix2[17037:207] didPushItem: <TableDisplay: 0x5d41cc0>
2010-10-13 02:12:45.912 Remix2[17037:207] Current items: (
    "<TableDisplay: 0x5d41cc0>"
)
2010-10-13 02:12:49.020 Remix2[17037:207] didPushItem: <WebDisplay: 0x591a590>
2010-10-13 02:12:49.021 Remix2[17037:207] Current items: (
    "<TableDisplay: 0x5d41cc0>",
    "<WebDisplay: 0x591a590>"
)
2010-10-13 02:12:49.023 Remix2[17037:207] Selected story: <WebDisplay: 0x591a590>
2010-10-13 02:12:59.498 Remix2[17037:207] didPopItem: <WebDisplay: 0x591a590>
2010-10-13 02:12:59.499 Remix2[17037:207] Current items: (
)
Run Code Online (Sandbox Code Playgroud)

CIF*_*ter 0

当您的子类实现该方法时,您始终必须[super awakeFromNib]根据以下文档进行调用-awakeFromNib

您必须调用 awakeFromNib 的超级实现,以使父类有机会执行它们所需的任何其他初始化

然而重要的是,...

我不明白为什么你必须实际管理自己的导航栏。如果您子类化UINavigationBar并且仅重写某些绘图或布局方法(例如-drawRect:-layoutSubviews等),那么在导航控制器中管理导航栏背后的所有逻辑都将依赖于原始UINaviationBar类。

我必须为几乎每个主要UIKit类进行广泛的视图自定义,但我总是将复杂的逻辑留给原始类,仅覆盖绘图方法来自定义外观和感觉。

顺便说一句,如果您所做的只是使用自定义图像资源,那么在不进行子类化的情况下为整个应用程序换肤实际上要容易得多。通过设置图层的属性,您可以根据需要或在整个应用程序中contents自定义基于 的类的外观和风格:UIView

#import <QuartzCore/QuartzCore.h>
...
- (void)viewDidLoad
{
    [super viewDidLoad];

    UIImage * navigationBarContents = [UIImage imageNamed:@"navigation-bar"];
    self.navigationController.navigationBar.layer.contents =    
        (id)navigationBarContents.CGImage;
}
Run Code Online (Sandbox Code Playgroud)

您可以为继承自 的任何类设置内容UIView:导航栏、工具栏、按钮等。这种方式管理起来要容易得多,根本不需要子类化。