对NavigationController/Bar/Item、self.navigationItem/self.navigationController.navigationItem区别的理解

这篇博客探讨了在iOS开发中NavigationController、Bar、Item之间的关系,以及self.navigationItem和self.navigationController.navigationItem的区别。文章解释了每个UIViewController如何通过NavigationItem显示标题,并指出UINavigationController负责生成UINavigationBar栈,每个UIViewController管理其在栈中的NavigationItem。同时,博客指出两者在使用上的等价性,但建议优先使用self.navigationItem,因为它更直接地关联当前控制器的NavigationItem。
摘要由CSDN通过智能技术生成

(刚学计算机的新手请先百度,学习什么是“栈”。本人简单形容:栈就相当于放在一个地上可以装书本的盒子,放进去的顺序为书本1、2、3,拿出来的顺序则为3、2、1)


每个ViewController只有一个NavigationItem属性,默认目的是显示当前视图控制器ViewController的主题(title)。

Xcode文档对NavigationItem是这么解释的(关键词:“NavigationItem”)

The default behavior is to create a navigation item that displays the view controller's title.


====================================================================


UINavigationController、UINavigationBar、UIViewController与UINavigationItem之间的关系:


UINavigationBar定义为UINavigationController的一个属性property:


UINavigationController栈负责生成UINavigationBar栈,但UINavigationBar栈中每个UINavigationItem的入栈出栈由UINavigationController中的每个对应的UIViewController管理(记住每个UIViewController都拥有一个UINavigationItem,默认用于显示当前UIViewController的标题title):


简单讲,全局唯一的UINavigationController栈生成全局唯一的UINavigationBar栈,UINavigationController中的每个UIViewController管理UINavigationBar(UINavigationController栈每个UIViewController将自身的属性:navigationItem压入或弹出UINavigationBar)。


两个栈——UINavigationController栈、UINavigationBar栈,从层次关系上来说,是一一对应的:


上方注释的意思,依个人理解,意思是:UINavigationController中当前活动的视图控制器UIViewController与UINavigationBar栈中当前活动的UINavigationItem一一对应,处于同一层次。

用下图来表示:

顺序一:


顺序二:


(感谢在线画图工具Gliffy Editor:https://www.gliffy.com/go/html5/launch?app=1b5094b0-6042-11e2-bcfd-0800200c9a66#


====================================================================


我们有时会发现ViewController的self.navigationItem、self.navigationController.navigationItem作用一样,它们之间有区别吗?


首先,self.navigationItem不难理解,代表当前控制器的UINavigationItem;

至于self.navigationController.navigationItem,需要先解释一下,self.navigationController是什么意思——

【苹果开发文档对UIViewController.navigationController属性的解释:】the nearest ancestor in the view controller hierarchy that is 

a navigation controller...if the receiver or one of its ancestors is a child of a navigation controller,this property contains the owning 

navigation controller.this property is nil if the view controller is not embedded inside a navigation controller.

可以简单理解为:self.navigationController代表访问全局UINavigationController中的当前活动视图(其实就是控制器自己)。如果当前控制器不处在UINavigationController中,则获取不到navigationController属性(值为nil);


概括为——每个UIViewController内部都定义了一个navigationController属性,它代表的是已被压入UINavigationController栈中的当前控制器自身(self)!

如果当前控制器未压入栈,self.navigationController=nil;如果控制器已压入栈,self.navigationController=self


现在就可以解答问题了:self.navigationItem、self.navigationController.navigationItem作用一样,但前提必须是此视图控制器已经压入全局的UINavigationController栈中。所以建议最好使用self.navigationItem,防止因当前视图控制器没有压入栈而调用不到控制器自身的navigationItem属性。


可能有人要问,已经有self指针了,那self.navigationController这种设计不是多次一举吗?本人的看法是,它可以用于判断当前控制器是否已被压入栈,以此做出不同响应,比如使用下方代码:

if(self.navigationController)
{
    //属性不为nil
    代码1
}
else
{
    //属性为nil
    代码2(比如提示未入栈警告)
}


好的,以下是用Objective-C纯代码实现的签到日期界面。实现的界面包括一个导航栏、一个显示当前日期的标签和一个签到按钮。 ViewController.h文件: ```objective-c #import <UIKit/UIKit.h> @interface ViewController : UIViewController @end ``` ViewController.m文件: ```objective-c #import "ViewController.h" @interface ViewController () @property (nonatomic, strong) UILabel *dateLabel; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. // 设置导航栏标题 self.navigationItem.title = @"签到"; // 设置背景颜色 self.view.backgroundColor = [UIColor whiteColor]; // 创建并添加日期标签 self.dateLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 50)]; self.dateLabel.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2 - 50); self.dateLabel.textAlignment = NSTextAlignmentCenter; self.dateLabel.textColor = [UIColor blackColor]; [self.view addSubview:self.dateLabel]; // 更新日期标签的文本 [self updateDateLabel]; // 创建并添加签到按钮 UIButton *checkInButton = [UIButton buttonWithType:UIButtonTypeSystem]; checkInButton.frame = CGRectMake(0, 0, 200, 50); checkInButton.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2 + 50); [checkInButton setTitle:@"签到" forState:UIControlStateNormal]; [checkInButton addTarget:self action:@selector(checkInButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:checkInButton]; } // 更新日期标签的文本 - (void)updateDateLabel { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.dateFormat = @"yyyy年MM月dd日"; self.dateLabel.text = [formatter stringFromDate:[NSDate date]]; } // 签到按钮点击事件 - (void)checkInButtonClicked:(UIButton *)sender { // TODO: 处理签到逻辑 // 更新日期标签的文本 [self updateDateLabel]; } @end ``` 在AppDelegate.m文件中,将ViewController设置为根视图控制器: ```objective-c #import "AppDelegate.h" #import "ViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; ViewController *viewController = [[ViewController alloc] init]; UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController]; self.window.rootViewController = navigationController; [self.window makeKeyAndVisible]; return YES; } ``` 这样就完成了一个简单的签到日期界面的实现。运行程序后,可以看到一个带有日期标签和签到按钮的界面。点击签到按钮后,日期标签上的日期会更新为当前日期。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值