1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Objective-C 在基本语言上做了两个扩展:范畴(categories)和协议(protocols),它们是强大的软件开发工具。这两个扩展引入了声明方法并将它们关联到某个类的技术。
感觉上,categories像是方法动态绑定,protocols像是接口而用于继承[虚方法]
非正式协议respondsToSelector [NSObject]
检查协议conformsToProtocol

正式协议有其自己的限制。如果协议声明的方法列表随着时间而增长,协议的采纳者就会不再遵循该协议。
因此,Cocoa 中的正式协议被用于稳定的方法集合,比如 NSCopying 和 NSCoding。如果您预期协议方法会增多,则可以声明为非正式协议,而不是正式协议。

Cocoa 提供了两个根类:NSObject 和 NSProxy。Cocoa 将后者定义为抽象类,用于表示其它对象的
替身对象。因此 NSProxy 类在分布式对象架构中是很重要的。由于作用比较特别,NSProxy 在 Cocoa
程序中出现频率很低。Cocoa 开发者在提到根类时,几乎总是指 NSObject。

NSObject
分配、初始化、和复制 [alloc init new copy]
对象的保持和清理 [retain release autorelease retainCount dealloc]
内省和比较 [superclass class isKindOfClass IsMemberOfClass isSubclassOfClass conformsToProtocol isEqual description]
对象的编码和解码 [encodeWithCoder initWithCoder classForCoder replacementObjectForCoder awakeAfterUsingCoder]
消息的转发 forwardInvocation
消息的派发 performSelector

在 dealloc 方法中,您则在最后一步调用超类的 dealloc 实现

类工厂方法的实现是为了向客户提供方便,它们将分配和初始化合在一个步骤中,返回被创建的对象,并
进行自动释放处理。这些方法的形式是+ (type)className...(其中 className 不包括任何前缀)。
工厂方法则可以避免为可能没有用的对象盲目分配内存
类工厂方法约定俗成地将返回对象放到自动释放池中

在碰到对象可变性的问题时,最好采纳一些防御性的编程实践

为对象制作快照以备后用的问题在于开销太昂贵,您需要为同一个对象制作多个拷贝。一个更有效的选择
是使用键-值观察协议。

子类必须重载它继承的、直接访问对象实例变量的所有方法,这样的方法称为基元方法(primitive methods)。类的基元方法是其接口的基础。

在接口上区分基元方法和衍生方法使子类的创建更加容易。您的子类必须重载通过继承得到的基元方法,
而重载基元方法之后就可以保证继承而来的衍生方法可以正确地工作。

Objective-C @synchronized深入理解 https://www.cnblogs.com/yangwenhuan/p/9193840.html

委托者对象需要公布一个被称为非正式协议的接
口,客户对象则必须首先注册为委托,然后实现该接口中的一个或多个方法。发布通告的对象要公布
自己广播的通告列表,而所有的客户对象都可以自由监听其中的一个或多个公告。
NSApplication、NSText、和 NSWindow 就是一些委托者类,而很多框架类都可以广播通告。

在满足自动观察者通知的基础上,简单地保证您的对象遵循 KVC 就可以使之遵循 KVO。然而,如果您选
择实现手工的键-值观察,就需要额外的工作。

设计模式在 Cocoa 框架中的主要实现方式,特别是模型-视图-控制器和对象建模模

1
2
3
4
5
6
7
8
9
协议是一个编程语言级别(Objective-C)的特性,它使定义适配器模式的实例成为可能(在 Java 中的“接口”和“协议”是同义的)。
如果您希望一个客户对象和另一个对象进行交流,但由于它们的接口不兼容而导致困难,您就可以定义一个协议,它本质上是一系列和类不相关联的方法声明。
这样,其它对象的类就可以正式采纳该协议,并通过实现协议中的全部方法来“遵循”该协议。结果,客户对象就可以通过协议接口向其它对象发送消息。
协议是一组独立于类层次的方法声明,这样就有可能象类的继承那样,根据对象遵循的协议对其进行分组。
您可以通过NSObject的 conformsToProtocol:方法来确认一个对象的协议关系。
除了正式协议之外,Cocoa还有一个非正式协议的概念。这种类型的协议是NSObject类中的一个范畴
(category),这样就使所有的对象都成为范畴方法的潜在实现者(参见 "范畴"部分)。
非正式协议的方法可以选择性地实现。非正式协议是委托机制实现的一部分(参见 "委托"部分。
请注意,协议的设计和适配器模式并不完全匹配。但它是使接口不兼容的类在得以协同工作的手段。
1
2
3
4
5
NSInvocation 对象是分布式、撤消管理、消息传递、和定时器对象编程接口的一部分。在需要去除消
息发送对象和接收对象之间的耦合关系的类似场合下,您也可以使用。
分布式对象是一种进程间通讯技术

有点像QObject connect
1
2
3
4
5
6
委托是在宿主对象中嵌入一个指向另一对象(也就是委托对象)的弱引用(一个未保持的插座变量),并
不时地向该委托对象发送消息,使其对有关的任务进行输入的机制。宿主对象一般是一个“复活”的框架对
象(比如一个 NSWindow 或 NSXMLParser 对象),它寻求完成某项工作,但又只能以一般的方式来
进行。委托几乎总是一个定制类的实例,它负责配合宿主对象,在有关任务的特定点(参见图 4-3)上提
供与具体程序有关的行为。这样,委托机制使我们可以对另一个对象的行为进行修改或者扩展,而不需要
生成子类。
1
2
3
4
NSImage 类为装载和使用基于位图(比如 JPEG、PNG、或者 TIFF 格式)或向量(EPS 或 PDF 格式)
的图像提供统一的接口。NSImage 可以为同一个图像保持多个表示,不同的表示对应于不同类型的
NSImageRep 对象。NSImage 可以自动选择适合于特定数据类型和显示设备的表示。同时,它隐藏了
图像操作和选择的细节,使客户代码可以交替使用很多不同的表示。
1
2
3
4
5
Foundation 框架中的 NSEnumerator 类实现了迭代器模式。NSEnumerator 抽象类的私有具体子类
返回的枚举器对象可以顺序遍历不同类型的集合—数组、集合、字典(值和键)—并将集合中的对象返回
给客户代码。
所有的枚举器的工作方式都一样。您可以在循环中向枚举器发送 nextObject 消息,
如果该消息返回 nil,而不是集合中的下一个对象,则退出循环。
1
2
3
4
在 Cocoa 中,控制器对象一般有两个类型:仲裁控制器或者协调控制器。
仲裁控制器负责仲裁应用程序中视图对象和模型对象之间的数据流。仲裁控制器通常是 NSController 对象。
协调控制器则负责实现应用程序的集中化通讯和控制逻辑,作为框架对象的委托和动作消息的目标。它们通常是NSWindowController 对象或定制 NSObject 子类的实例。
由于协调控制器高度专用于特定的程序,因此不考虑重用。
1
2
3
几乎任何一对对象之间都可以建立绑定关系,只要它们遵循 NSKeyValueCoding 和
NSKeyValueObserving 这两个非正式协议。但是,我们推荐您通过仲裁控制器来建立绑定,以得到
NSController 及其子类为您提供的各种好处。
1
2
有几个 Cocoa 框架类采用单件模式,包括 NSFileManager、NSWorkspace、和 NSApplication
类。这些类在一个进程中只能有一个实例。当客户代码向该类请求一个实例时,得到的是一个共享的实例,该实例在首次请求的时候被创建。
1
2
3
4
5
6
7
8
9
10
11
视图对象和模型对象应该是程序中最具可重用性的对象。视图对象代表操作系统及操作系统支持的应用程序的“观感”;外观和行为的一致性是很重要的,这就要求对象是高度可重用的。顾名思义,模型对象负责对问题域的关联数据进行封装,以及执行相关的操作。从设计的角度上看,最好让模型对象和视图对象彼此分离,因为这样可以增加它们的可重用性。

委托几乎总是您的一个定制对象,它通过定义将应用程序具体逻辑结合到程序中,而这些逻辑是
具有一般性的,是向外委托任务的对象自身不可能知道的。
理解通告和委托消息的关系是很重要的。向外委托的对象自动使自己的委托成为自己发出的所有通告
的观察者。委托需要做的是实现相关联的方法,以获取通告。

由于控件开销比较大,我们就通过单元将其在屏幕上的空间划分成不同的功能区域。单元是轻
量级的对象,我们可以将它考虑为覆盖全部或部分控件的区域。但它不仅是区域的分割,还是对任务的分
割。单元负责一些本来由控件描画的工作,而且保有一些本来由控件保有的数据,其中的两项就是目标和
动作的实例变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
尽管常规的通告中心允许任何对象作为通告对象(也就是通告封装的对象),分布式通告中心只支持将
NSString 对象作为它的通告对象。由于发出通告的对象和通告的观察者可能位于不同的任务中,通告
不能包含指向任意对象的指针。因此,分布式通告中心要求通告使用字符串作为通告对象。通告的匹配就
是基于这个字符串进行的,而不是基于对象指针。

当然,当您希望通过聚结移除队列中类似的
通告时,应该用 enqueueNotification...方法,且使用 NSPostNow 风格,而不是使用
postNotification:方法。

除了保证单件实例之外,sharedApplication 方法主要做什么呢?它还负责建立一些程序的基础设
施,以便接收和处理来自窗口服务器的事件。在初始化全局应用程序对象的过程中,NSApplication
通过生成一个接收事件的事件源建立一个与窗口服务器的连接(实现为一个 Mach 端口),并建立一个应
用程序事件队列,即一个 FIFO(先进先出)的机制,使事件在到达事件源时被取出,并放入队列等待处理。
最后,NSApplication 将事件源作为输入源,对主运行循环,即主线程的运行循环,进行初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
由于有缓冲的窗口对于透明和非矩形的形状是必需的,所以几乎所有的 Cocoa 窗口都是有缓冲的。无保持的窗口适用于临时的图像或简单的连接线,比如 Interface Builder 中的目标-动作连接。

窗口可以被显式地从屏幕列表中拿掉,在这种情况下,我们称之为离屏窗口。当一个窗口从列表中移走时,会从屏幕上消失;而当它被放入列表中时,就会再次回到屏幕上。事件不被派发到离屏的窗口上。应用程序对窗口进行隐藏,就是基于从屏幕列表中移走窗口来实现的。离屏窗口必需被缓冲或者保持,才能支持描画。

一个视图可以锁定焦点,描画自身,然后解锁焦点。但是这种做法只在特定的场景下推荐,比如在定时器的回调函数中对视图内容进行动画显示。一般地说,您不应该绕过 Application Kit 的显示机制。
NSView -> lockFocus/unlockFocus 10.15弃用

视图的描画不一定需要发生在主线程;应用程序的每一个线程都有能力锁定视图的焦点并进行描画。然而
有下面这些限制:
- NSView 对象属性(比如它的边框矩形)的改变应该只发生在主线程。
- 当 NSView 的显示方法被调用时,Application Kit 会设置一个锁,以便在接收视图的窗口中描画;
在显示方法返回之前,您不能年执行任何定制的描画。这意味着,同时只有一个线程可以在指定窗口
中进行描画。

控件是完全功能的 NSView 对象,它们可以被标识为需要显示,并负责描画自身所在的区域;也可以响应
用户事件,属于响应者链中的对象。
单元是一种抽象,用于简化视图中不同类型的图形对象的管理。它使我们得到一种插件设计,使控件
可以作为不同图形对象的宿主,这些图形对象可以有自己的标识,包括目标和动作信息。

和使用子视图相比,使用单元进行子区域的描画也有一些折衷的地方。由于没有视图失效的机制,控件必
须自行计算每个单元需要描画什么。但是由于视图是用于一般目的的对象,而控件是具有专门目的的,通
常可以更有效地完成所需的计算。
1
非正式协议为一个可以选择性实现的一系列方法列表。非正式协议虽名为协议,但实际上是挂于NSObject上的未实现分类(Unimplemented Category)的一种称谓,Objetive-C语言机制上并没有非正式协议这种东西,OSX 10.6版本之后由于引入@optional关键字,使得正式协议已具备同样的能力,所以非正式协议已经被废弃不再使用。