参考文献:
iOS的MVC框架
iOS--KVO的实现原理与具体应用
一. 基础架构:MVC
先上两张图帮助记忆IOS中MVC架构的工作方式:
1. 单个MVC结构
从图上可知Model、View、Controller三者的关系是:
-
Model:当视图层中用于创建或修改数据的用户操作通过控制器对象进行通信,从而创建或更新模型对象。当模型对象发生更改时(例如,通过网络连接接收新数据),它会通知控制器对象,该对象会更新相应的视图对象。
-
View:查看对象通过应用程序的控制器对象了解模型数据的更改,并将用户启动的更改(例如,在文本字段中输入的文本 - 通过控制器对象 - 传递到应用程序的模型对象。
-
Controller:控制器对象解释在视图对象中进行的用户操作,并将新的或更改的数据传递给模型层。当模型对象发生更改时,控制器对象会将新模型数据传递给视图对象,以便它们可以显示它。
2. 多个MVC协同工作
MVC分别用来实现哪些代码?
- Model:负责业务逻辑、来自UI数据处理、本地数据、网络接收数据。
- View:负责实现屏幕展示的UI、响应用户事件。
- Controller:负责View与Model间的消息的转发传递。
注意:
不论Model、View还是Controller都可以不只是一个类,它们每个角色都可以有多个。只是从职责上划分后某个Class必须是MVC中的一员与软件的三层架构有异曲同工之妙。
Model的类永远不与View的类直接交互。
本次工程实践中,目前完成的代码全部遵循MVC架构的原则,但是MVC也存在其不足之处,在日后迭代的过程中需要进行重构。
二. IOS中的观察者模式:KVO机制
1. KVO是什么?
- KVO 是 Objective-C 对观察者设计模式的一种实现。
- KVO提供一种机制,指定一个被观察对象(例如A类),当对象某个属性(例如A中的字符串name)发生更改时,对象会获得通知,并作出相应处理;且不需要给被观察的对象添加任何额外代码,就能使用KVO机制
- 在MVC设计架构下的项目,KVO机制很适合实现mode模型和view视图之间的通讯。
2. KVO实现原理
基本的原理:
- 当观察某对象A时,KVO机制动态创建一个对象A当前类的子类,并为这个新的子类重写了被观察属性keyPath的setter 方法。setter 方法随后负责通知观察对象属性的改变状况。
深入剖析:
-
Apple 使用了 isa 混写(isa-swizzling)来实现 KVO 。当观察对象A时,KVO机制动态创建一个新的名为: NSKVONotifying_A的新类,该类继承自对象A的本类,且KVO为NSKVONotifying_A重写观察属性的setter 方法,setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象属性值的更改情况。
-
NSKVONotifying_A类剖析:在这个过程,被观察对象的 isa 指针从指向原来的A类,被KVO机制修改为指向系统新创建的子类 NSKVONotifying_A类,来实现当前类属性值改变的监听;
-
所以当我们从应用层面上看来,完全没有意识到有新的类出现,这是系统“隐瞒”了对KVO的底层实现过程,让我们误以为还是原来的类。但是此时如果我们创建一个新的名为“NSKVONotifying_A”的类(),就会发现系统运行到注册KVO的那段代码时程序就崩溃,因为系统在注册监听的时候动态创建了名为NSKVONotifying_A的中间类,并指向这个中间类了。
-
isa 指针的作用:每个对象都有isa 指针,指向该对象的类,它告诉 Runtime 系统这个对象的类是什么。所以对象注册为观察者时,isa指针指向新子类,那么这个被观察的对象就神奇地变成新子类的对象(或实例)了。
-
因而在该对象上对 setter 的调用就会调用已重写的 setter,从而激活键值通知机制。
-
子类setter方法剖析:KVO的键值观察通知依赖于 NSObject 的两个方法:willChangeValueForKey:和 didChangevlueForKey:,在存取数值的前后分别调用2个方法:
-
被观察属性发生改变之前,willChangeValueForKey:被调用,通知系统该 keyPath 的属性值即将变更;当改变发生后, didChangeValueForKey: 被调用,通知系统该 keyPath 的属性值已经变更;之后, observeValueForKey:ofObject:change:context: 也会被调用。且重写观察属性的setter 方法这种继承方式的注入是在运行时而不是编译时实现的。
三. 系统视图:软件架构的描述方法
软件架构模型是通过一组关键视图来描述的,同一个软件架构,由于选取的视角(Perspective)和抽象层次不同可以得到不同的视图,这样一组关键视图搭配起来可以完整地描述一个逻辑自洽的软件架构模型。一般来说,我们常用的几种视图有分解视图、依赖视图、泛化视图、执行视图、实现视图、部署视图和工作任务分配视图
1. 分解视图
分解是构建软件架构模型的关键步骤,分解视图也是描述软件架构模型的关键视图,一般分解视图呈现为较为明晰的分解结构(breakdown structure)特点。分解视图用软件模块勾划出系统结构,往往会通过不同抽象层级的软件模块形成层次化的结构。由于前述分解方法中已经明确呈现出了分解视图的特征,我们这里简要了解一下分解视图中常见的软件模块术语。
- 子系统(Subsystem),一个系统可能有一些列子系统组成;
- 包(Package),子系统又由包组成;
- 类(Class),包又由类组成;
- 组件(Component),一般用来表示一个运行时的单元;
- 库(Library)是具有明确定义的接口的共享软件代码的集合,可以是代码库,也可以是由代码库编译打包后的静态库,还可以构建成动态链接库;
- 软件模块(Module)用来指软件代码的结构化单元,模块化(modular)是在软件架构中各部分都被明确定义的接口所描述时使用,也就是可以明确无误地指定各部分的外部可见行为。
- 软件单元(Software unit)是在不明确该部分的类型时使用。
2. 依赖视图
3. 执行视图-时序图
4. 实现视图-目录结构
四. 数据层设计-网络请求字段
用户信息
| 字段名称 | 字段类型 | 字段描述 |
|---|---|---|
| id | long | ID |
| acount | string | 账号 |
| authority | int | 权限 |
| certificateNO | string | 证件号码 |
| certificateType | int | 证件类型 |
| mobilePhoneNO | string | 手机号码 |
| gender | int | 性别 |
| name | string | 姓名 |
| passwd | string | 密码 |
| info | string | 附加信息 |
日历
| 字段名称 | 字段类型 | 字段描述 |
|---|---|---|
| year | int | 年 |
| month | int | 月 |
| day | int | 日 |
| week | int | 星期 |
| lunarCalendar | string | 农历日期 |
| holiday | string | 节假日 |
| presellDay | int | 预售时长 |
车站表
| 字段名称 | 字段类型 | 字段描述 |
|---|---|---|
| normalStation | array | 所有车站集合 |
| hotStation | array | 热门城市车站集合 |
| searchHistory | array | 查询历史记录 |
ticket
| 字段名称 | 字段类型 | 字段描述 |
|---|---|---|
| ID | long | ID |
| arrivalStation | string | 到达车站 |
| startStation | string | 始发车站 |
| arrivalTime | string | 到达时间 |
| startTime | string | 始发时间 |
| trainNO | string | 车次 |
| carriageNO | int | 车厢号 |
| seatNO | int | 座位号 |
| price | int | 价格 |
| quantity | int | 余票量 |
订单
| 字段名称 | 字段类型 | 字段描述 |
|---|---|---|
| Id | long | ID |
| userInfo | user | 用户信息 |
| ticketInfo | ticket | 车票信息 |
| orderTime | string | 预定时间 |
| status | int | 订单状态 |
| info | string | 其他信息 |
五. 技术选型
- 编程语言:Objective-C
- IDE:XCODE 12
- 基础架构:MVC
- View框架:IOS UIKit
- 基础框架:IOS Foundation
- 网络框架:AFNetworking
- 网络数据传输格式:JSON
- 部署环境:IOS移动端设备,IOS 11 以上版本
- 开源库管理工具:CocoaPods
六. 系统概念原型的核心工作机制
- 用户首先需要注册账号、输入规定的信息、登录账号
- 然后通过选择车站、日期查询车票信息
- 接着选择车票,或帮助他人选票,系统将自动安排座位,生成订单
- 订单可在一定时间内延迟支付,用户若点击支付,则完成支付
- 用户可根据订单页查询订单信息,可进入“我的”页修改信息、更换账号
- 由时序图可以看到,除日期数据是本地存储以外,其余操作相关数据都要通过网络请求从服务器中得到