macOS开发入门之二:macOS App剖析
欢迎回到《macOS开发入门》!
- 1.在第一部分教程中,我们学习了如何获得macOS app开发所需的工具,以及探索Xcode,学习了如何构建和运行macOS app以及UI设计。
- 2.在第二部门教程中,我们将在Xcode中剖析macOS app的组件。 从macOS app启动的方式,到UI如何构建再而如何用户处理交互进行一个系统性了解。
- 3.在最后部分你将自己上手操作,从无到有的建立你的第一个macOS app。
本文面向完整本系列教程第一部分学习的或者有Xcode使用经验的开发者。我们假定你对macOS app的体系结构了解甚少,如果您已经熟悉macOS的体系结构,那么您可能需要跳过,直到跳到最后一部分。
在本文末尾你将打下一个良好的基础,对macOS app的不同部分如何结合有一个初步的理解,即使可能不知道它们各自如何工作。
提示: 本部分只是讲解macOS app工作原理的背景信息,不涉及代码编写。
只需要坐下来轻松的学习,我们再下一个部分才会编写代码。
macOS app如何启动?
让我们从macOS app的启动来开始我们的学习,在app启动时有三个组件需要我们注意:
- 1.AppDelegate.swift:代码运行的入口,
AppDelegate.swift
是一个很重要的文件,负责提供app在整个生命周期中(启动、闲置、进入后台、进入前台、激活、完全退出)与操作系统交互的方法。在运行代码时为你提供来自macOS的通知,例如Handoff请求、命令行参数和推送通知等。 - 2.Main.storyboard:故事板具有指定的“入口点”,这允许系统在app启动时构建UI,这个入口点如图所示:
你可以很清晰的看出来哪些场景将构建出app的初始UI界面。
- 3.Info.plist:在一个app中可以有多个storyboard,那么macOS怎么知道用哪一个来构建初始UI呢?我们可以在
Info.plist
文件中向操作系统提供这个信息,如下图:
Info.plist
文件包含了大量有用的app配置选项,其中许多可以通过Xcode的目标配置面板显示。下图显示了如何在更友好的界面中进行同样的初始storyboard配置:
启动app比较复杂,但这对三个文件的解释您可以了解在哪里交互和配置app的启动选项。现在你已经让你的app运行了,是时候来看看一个非常重要的东西了——app的用户界面UI。
用户界面UI(User interface)
你已经知道app的UI界面是有故事板 storyboard
提供的,在本节中我们将了解不同的UI组件,它们能够提供的效果以及它们如何组织在一起。
Window
你的macOS app可能有一个或多个窗口对象(window objects),窗口就是app负责提供UI组件的一块屏幕区域。当用户更改app的窗口位置或大小时,macOS通过一个window manager来处理。
除了表现app的可视化外观,窗口对象还处理用户使用鼠标和键盘在进行用户交互(user interaction)时所触发的用户事件(user events)。
尽管可以直接与窗口对象(window objects)交互,但是通常窗口对象由窗口控制器(window controllers)管理,特别是在与故事板(storyboards)结合使用的时候。
窗口控制器负责加载窗口对象本身,并允许你在窗口运行周期中挂载不同的事件。
故事板包含至少一个窗口控制器,如图:
窗口控制器(window controllers)是通过NSWindowController类(NSWindowController class)来表现的。当你在配置不同的窗口时,通常要创建不同的子类(subclasses)来实现不同的需求。
Views
窗口提供了app的UI界面的绘图区域,但不负责绘图。由自定义视图(views)负责在屏幕上绘制UI界面。
视图(views)是矩形的,由NSView类(NSView class)表现。视图(views)存在于多层次结构中,即:任何视图可以包含零到多个子视图,允许你使用简单的、可复用的视图组件构建复杂的布局(layout)。
View Controllers
和窗口控制器在故事板中管理窗口一样,视图(views)由视图控制器类(view controller class)管理。视图控制器(view controller)通过直接操作属性或者Cocoa bindings技术,将视图层(view hierarchy)和模型层(model layer)链接起来,这是典型的MVC模式(Model–View–Controller):
使用视图控制器的好处就是易于复用(reusable),减少重复工作,提高效率。
视图控制器由 NSViewController
表现,允许你在app生命周期中随时执行自定义操作。例如,当视图即将通过 viewWillAppear()
显示在屏幕上时,你可以触发动画;或者在视图层已由 viewDidLoad()
正确加载之后,使用数据填充相关视图。
你的app很可能由一些NSViewController的自定义子类组成,每个子类负责窗口的不同部分。它们是一个app的重要内容,帮助你将基础数据呈现给用户。
View components
AppKit
包含了大量常用的NSView子类,你可以使用它们在屏幕上显示内容。
下面是一些常用的例子:
- Label:显示静态文本,可设置字体和外观。
- Text Field:用户可编辑的文本控件。 用于从用户收集字符串。
- Image View:由NSImage object绘制单张图片。
- Push Button:众多的按钮类型之一,用于响应用户的鼠标点击动作。
- Table View:用于显示数据集合的许多视图子类的一个列表实例。
这些只是一些构建UI界面时常用的视图子类,你可以在Interface Builder的Object library中找到更多:
Viewing collections
通常情况下,你会希望在你的app的UI界面中同时显示多个模型对象,如:显示一个约会列表、显示相册一张照片。
macOS提供了两种方式来显示模型对象集合,列表视图和集合视图。
和名字一样,列表视图用于显示表格数据,每行一个模型对象,每列显示这些对象的不同属性。
列表视图由单元格组成,可以在屏幕上滚动并在视图之外被回收,数据可以通过一个数据源协议或使用Cocoa Bindings提供。
表格支持排序,编辑和自定义单元格,为您提供了一个非常强大的数据显示视图。
集合视图也是由单元格的集合组成,但是每个单元格就是一个模型对象。这些单元格的布局是完全可自定义的。
和列表视图类似,集合视图数据可以通过一个数据源协议或使用Cocoa Bindings提供.单元格在视图之外时也会被回收,以减少内存占用。
集合视图已内置支持单元格选择、重新排序和分组单元格。
处理用户交互
用户可以使用鼠标、键盘、触摸板以及其他输入设备与macOS系统进行交互。为了协助用户向app输入信息,macOS提供了一个围绕响应者链(responder chain)概念建立的统一的事件分派模型。
通过键盘按键生成的事件称为Key Events,事件通过复杂的路径才能到达app。一些键盘按键事件会被截取在操作系统级别(电源按钮、屏幕亮度、音量),它们不会到达你的app。
Key Events可以是单个按键或组合按键,当事件到达app时,会首先检查它们是否被绑定到菜单项的键盘快捷键。
如果没有被绑定,则再检查它们是否用于浏览你的app的UI用户界面,例如按 Tab
键切换输入框。如果也不是这种情况,窗口在传递Key Events之前会确定当前活动视图(第一响应者,first responder)。这些键盘事件可以解释为对视图的命令或者输入字符。
键盘输入很复杂,因为它可以影响系统和应用程序架构的许多级别,但macOS协助处理它的过程又较长。 在许多情况下,你会发现它“开箱即用”。
鼠标类的事件,先它们被执行的窗口和视图,再传递到相应的自定义子类,事件才会得到适当的处理。响应者类(responder class)包括了点击和移动鼠标时调用的方法(methods)。
触摸板(trackpad)为传统鼠标提供了大量的额外手势,从iOS借来了手势识别器(gesture recognizer)的概念。这样可以把多指触碰动作解释为语义动作,如平移、旋转等。
手势识别器提供了更高水平的鼠标事件的解释,并且将它们与视图相关联,并且可以拦截与该视图相关联的所有类似鼠标的事件。
macOS中的事件处理体系结构相当复杂,但是缺省情况对于处理许多常见情况有很大的帮助。 依赖于响应者链的强大力量,使得在最高级别处理相关事件变得很容易。
菜单 Menus
菜单是与app关联的不同操作的集合,可以出现在不同的地方,包括:
- Menu Bar 即菜单栏,依附于屏幕顶部:
- Context Menus 上下文菜单,即右键菜单,当用户鼠标右键点击时出现:
- Dock Menu 当用户长按或右键点击Dock图标时出现:
这些菜单你都可以在Interface Builder中进行配置,你可以编辑它们的外观、出现的层次结构以及每个项目关联的操作。
数据层
用户界面UI是macOS app中非常重要的一部分,但它可能不是你的app的全部。大多数app提供了一个用户界面,以便用户可以与底层数据模型进行交互。
数据模型在很大程度上取决于您的app所在的域(AppDomain),构建数据层没有神奇的解决方案。 事实上,通常你将使用Swift中提供的面向对象语言功能来创建一组对app的域进行建模的对象。
非常重要的是,数据层应该从用户界面UI分离出来,使您的app更易于维护并且不易出错。macOS通过Cocoa Bindings支持这种架构,Cocoa Bindings是一种将模型对象连接到UI并确保它们自动保持同步的技术。
你可以创建一个完全独立的动态框架来包含数据层,将其与UI层完全分离。 这可以允许在多个应app中使用相同的数据层, 甚至可能在macOS app和iOS app之间共享,并提高可测试性。
虽然你可以创建自己的数据层,但苹果提供了一个名为Core Data的框架。 这是一个用于创建对象图(object graph)以将整个数据层完全建模的全面框架。 它支持将模型对象的状态持久性存储到磁盘、数据验证、撤销等。
Core Data为Cocoa Bindings提供了强大的支持。这意味着你可以使用Core Data后端,轻而易举的对UI界面进行模型编辑,从而快速创建大量应用程序。
其他有用的Cocoa功能
这篇文章简单阐述了一些常用的Cocoa概念,它们只是这个非常丰富的平台的冰山一角。Cocoa其他的一些功能在构建强大的macOS app时非常有用:
- Networking:除了访问最低级别的网络功能之外,macOS还提供了一个更高级别的API来处理HTTP请求。 网络模型围绕异步会话构建,无缝处理上传和下载的任务列表。
- Location:您可以提供基于定位的服务(主要基于移动设备),但是您可以通过使用Core Location的定位或者MapKit的地图功能获得强大的支持。
- WebKit:Safari是顶级的Web浏览器之一,你可以通过WebKit将强大的渲染引擎集成到你自己的app中。它还包括与内容交互以及渲染HTML内容的能力。