使用良好的设计原则访问 UINavigationItem

Posted

技术标签:

【中文标题】使用良好的设计原则访问 UINavigationItem【英文标题】:Accessing UINavigationItem with Good Design Principles 【发布时间】:2015-06-02 04:11:55 【问题描述】:

我正在开发一个 ios 应用程序,其中我们有一个名为 FlowController 的类,它管理一组UIViewControllers 的流。

所以我们的基本结构是我们创建一个 FlowController 的实例,它创建一个UINavigationController,然后创建子视图控制器以在用户与视图控制器的视图交互时推送到导航控制器。

如果用户与与流程相关的视图进行交互,视图控制器会将该操作委托给流程控制器,流程控制器然后管理将新视图控制器推送到导航堆栈。

这样做的目的是将流程代码保留在视图控制器之外,以使我们的视图控制器更加模块化。

随着我们开发这个概念并且我们的设计师开始在我们的应用程序中添加更多UIBarButtonItems,我意识到我可以在 FlowController 中将UIBarButtonItems 添加到UIViewController's -navigationItem 属性,目标是 FlowController 和选择器作为流控制器中的选择器。

例子:

//Code in FlowController

-(void) startFlow
    UIViewController* firstViewController = [[UIViewController alloc] init];
    firstViewController.navigationItem.rightBarButtonItem = [self nextBarButtonItem];

   [self.navigationController pushViewController:firstViewController animated:TRUE completion:nil];


-(UIBarButtonItem*) nextBarButtonItem
    return [[UIBarButtonItem alloc] initWithTitle:@"Next" target:self selector:@selector(next:)];


-(void) next:(id) sender
    UIViewController* secondViewController = [[UIViewController alloc] init];

    [self.navigationController pushViewController: secondViewController animated:TRUE completion:nil];

这样我认为我的代码效率很高,因为我们有几个屏幕使用相同的视图控制器,但在导航栏中有不同的栏按钮项。

当我与我的一位同事谈论此事时,他说这违反了设计原则,因为我正在从视图控制器外部访问“视图”代码。

具体来说,我在 FlowController 中创建了UIBarButtonItems。他告诉我,我们不应该从除了 aUIViewController 子类之外的任何东西之外访问 aUIViewController's -navigationItemproperty,而且我所做的是打破了面向对象的封装设计原则。

他建议我应该在 aUIViewController 上创建方法,这些方法采用目标和选择器,将UIBarButtonItems 添加到视图控制器的 -navigationItem 内部。然后在 FlowController 中调用该方法。

例子:

//Code in UIViewController

-(void) addRightBarButtonItemWithTitle:(NSString*) title target:(id) target selector:(SEL) selector
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:title target:target selector:selector];


//Code in FlowController

-(void) startFlow
    UIViewController* firstViewController = [[UIViewController alloc] init];
    [firstViewController addRightBarButtonItemWithTitle:@"Next" target:self selector:@selector(next:)];

   [self.navigationController pushViewController:firstViewController animated:TRUE completion:nil];

我最初的直觉是不同意这一点,但是因为 FlowController 在我们的 MVC 应用程序的“控制器”部分的范围内,并且应该允许控制器访问视图。此外,如果我按照同事的建议进行操作,我将不得不添加一个

-addRightBarbuttonItemWithTitle:target:selector

我拥有的每个视图控制器上的方法或创建每个视图控制器必须继承的子类。

对于“封装”的想法以及限制性地将接口包装到 navigationItem 的想法,这似乎有很多开销和不必要的依赖(因为现在我只能有 -rightBarButtonItemwith 文本;没有图像或自定义视图。

所以终于解决了我的问题:从 aUIViewController 子类外部访问 aUIViewController's -navigationItemproperty 是不是很糟糕?如果是这样,苹果为什么要公开它? (我知道受保护的概念在 Objective C 中并不真正存在,但在仍然公开可用的 Swift 中确实存在。)

【问题讨论】:

不要像故事一样写问题。 【参考方案1】:

恕我直言,流控制器是否应该填充navigationItems 取决于您如何看待它:

如果(步骤)视图控制器的导航项依赖/链接/与视图控制器的内容有某种关系,那么它们应该由视图控制器决定。这进一步分为两种情况:

如果步骤视图控制器被设计为一个独立的组件,它不知道流程,并且可以在没有流程的情况下生存,那么它应该提供配置导航项的方法,以及分配处理程序的钩子(委托)导航项的事件。 “配置”是指您同事的建议。 如果步骤视图控制器是流程的一部分,并且知道其所有者流程控制器,它可以直接调用流程控制器的方法(例如nextSteppreviousStep)。

如果(步骤)视图控制器的导航项完全独立于视图控制器的内容——换句话说,步骤视图控制器有能力拥有一些导航项,但它不关心它的导航项——然后流控制器可以直接修改这些导航项。这就是你最初所做的。

在 Obj C 和 Swift 中,navigationItems 是公共的,并且通常从 Obj C 迁移的方法/属性在 Swift 中变为公共的。 Swift 和 Obj C 都没有“受保护”的概念,Apple 似乎不在乎 (inheritance, or not?)。

【讨论】:

以上是关于使用良好的设计原则访问 UINavigationItem的主要内容,如果未能解决你的问题,请参考以下文章

如何设计一个良好的接口

ADI的良好接地指导原则

如何设计一个良好的接口

面向对象设计原则

面向对象设计原则

设计模式-----里氏替换原则