2.6 KiB
2.6 KiB
对象协议:身份、复制与依赖
原书依据:第 7 章,印刷页 31–39,PDF 页 42–50。
Object 提供许多基础协议。阅读子类时,既要看它新增了什么,也要看它重写了什么。
身份与相等
== 判断是否为同一对象;= 表达由类定义的相等关系。两个内容相同的集合可以是两个不同对象。修改其中一个是否影响另一个,还取决于它们内部引用是否共享。
class 返回所属类。isMemberOf: 针对确切的类;isKindOf: 包含继承关系。检查 nil 通常使用 isNil 或 notNil。面向协议设计时,不必为了发送每条消息都先做具体类判断。
浅复制复制的是哪一层
原容器 ──→ 可变子对象
副本 ──→ 同一个可变子对象
浅复制产生新的外层对象,内部引用仍可指向相同子对象。给副本的某个槽位重新赋值,与修改该槽位所指子对象,是两种不同操作:前者改变副本自己的引用,后者可能被原对象观察到。
原书还讨论 deepCopy 和可被子类重写的 copy。深复制不应简单等同于“任意对象图都可以安全递归复制”:循环、共享关系和外部资源需要实现策略。本文没有对这些情况做运行验证。
表示与动态发送
| 消息 | 主要意图 |
|---|---|
printString |
得到便于人阅读的表示 |
storeString |
得到用于重建对象的源文本表示 |
perform: |
用符号指定要发送的消息 |
perform:with: |
动态发送带一个参数的消息 |
可读表示不等于持久化格式。动态发送也不是解析任意源代码:perform: 选择一个消息,而编译器求值会解释完整表达式。
用依赖通知连接对象
原书的依赖协议包含 addDependent:、removeDependent:、changed: 和 update:。模型改变后通知依赖者,让视图自行读取需要显示的状态。
视图注册到模型
↓
模型状态修改 → changed: 某方面
↓
依赖者收到 update: → 重新读取模型 → 更新显示
通知描述“需要更新”,并不天然携带完整的新状态。实现时要明确通知粒度、订阅解除和是否可能形成递归更新。原书的键盘互斥示例说明对象之间可以靠依赖关系协调状态;最后的 MVC 案例继续使用这套机制。
阅读检查点
对一个复制操作,画出复制前后的引用箭头;对一次通知,列出谁订阅、谁修改、谁通知、谁重绘。这两张简图往往比逐个记忆方法名更能暴露误解。