- 这篇文章由很多平时的笔记积攒而成,看起来会有些杂乱,会有很多需要改进的地方,希望发现问题的朋友不吝赐教。
类簇
我将苹果官方文档中的有关类簇的部分翻译了过来,
抽象工厂
抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。很多人会混淆抽象工厂模式和工厂模式。实际上,两种的差别还是比较明显的,如下表。
| 抽象工厂模式 | 工厂模式 |
|---|---|
| 通过对象组合创建抽象产品 | 通过类继承创建抽象产品 |
| 创建多系列产品 | 创建一种产品 |
| 必须修改父类的接口才能支持新的产品 | 子类化创建者并重载工厂方法以创建新产品 |
有关抽象工厂的东西我们先讲到这里,剩下的我们有时间再聊。
再往下就是针对具体情况的分析了,这段比较冗长,不喜欢的可以直接跳到最后一部分。
点击它来查看子类的名称,有些子类实在是过于稀少,就不单独拿出来说明了。
NSArray
《Effective Objective-C 2.0》中有一段话:
在使用了NSArray的alloc方法来获取实例时,该方法首先会分类一个属于某类的实例,此实例充当“占位数组”。该数组稍后会转为另一个类的实例,而那个类则是NSArray的实体子类。
__NSSingleObjectArrayI,需要说明它的用意:
__NSSingleObjectArrayI
__NSArrayI必须要实现
-
- count
-
- 再深入一点的说明一下,__NSSingleObjectArrayI是不需要去记录字符串长度的。它会比__NSArrayI少8个字节的长度。苹果可能是为了优化性能考虑,从而在iOS8之后推出这个新的子类。
另外需要说明的是,实际上,__NSArrayM本身只有7个方法,分别是:
- count
-
- objectAtIndex:
-
- insertObject:atIndex:
-
- removeObjectAtIndex:
-
- addObject:
-
- removeLastObject
-
- replaceObjectAtIndex:withObject:
所有其它高等级的抽象建立在它们的基础之上。例如 - removeAllObjects 方法简单地往回迭代,一个个地调用 - removeObjectAtIndex:。
NSDictionary
过程是
...
@property (nonatomic, copy) NSMutableDictionary *mutableDictionary;
...
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc]init];
[dictionary setObject:@"aaa" forKey:@"name"];
self.mutableDictionary = dictionary;
...
不可变字典。也就是说,对它进行改变的操作,会导致程序崩溃。崩溃信息如下:
2018-08-25 09:23:45.214879+0800 setget[90992:17397034] -[__NSFrozenDictionaryM setObject:forKey:]: unrecognized selector sent to instance 0x6000000dde40 2018-08-25 09:23:45.238002+0800 setget[90992:17397034] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSFrozenDictionaryM setObject:forKey:]: unrecognized selector sent to instance 0x6000000dde40'
__NSFrozenArrayM,不过我没有找到触发条件。不过应该与它类似。
NSSet
这里说明一下,__NSSingleObjectSetI不需要打扰实际的哈希表,因为只有一个对象需要担心。类似的方法containsObject:不需要遍历任何东西或查找任何东西,它可以简单地将参数与set / array / dictionary表示的单个对象进行比较。
NSString
object_getClassName方法打印对象。
我们可以发现,这里出现了三个子类
- __NSCFConstantString
- __NSCFString
- NSTaggedPointerString
__NSCFConstantString
念纪的这篇博客
__NSCFString
这个就是可变的NSString所属的子类了。不必多说。
NSTaggedPointerString
苹果将一个对象的指针拆分成了两部分,一部分直接保存数据,另一部分作为特殊标记(tag),表示这个是一个特别的指针。这样呢,就会将节省很多的时间,因为它不在需要正常创建对象的申请和创建空间,处理引用计数,以及直接读取(在objc_msgSend当中,Tagged Pointer会被识别出来,直接从指针中读取)。
- 苹果之前说过,使用Tagged Pointer技术之后,在内存上读取的速度快了3倍,创建时的速度比以前快乐106倍。
object_getClass()。
总结
类簇的优点在于:
- 1.可以将抽象基类背后的复杂细节隐藏起来
- 2.程序员不会需要记住各种创建对象的具体类实现,简化了开发成本,提高了开发效率
- 3.便于进行封装和组件化
- 4.减少了if else 这样缺乏扩展性的代码
- 5.增加新功能支持不影响其他代码
缺点也很明显:
- 已有的类簇非常不好扩展!!!
我们了解类簇的好处:
- 出现bug时,可以通过崩溃报告中的类簇关键字,快速定位bug位置。
- 举个例子:针对不同版本,不同机型往往需要不同的设置,这时可以选择使用类簇;
- app的设置页面这种并不需要经常修改的页面,可以使用类簇去创建大量重复的布局代码。
资料来源
Friday Q&A 2015-07-31: Tagged Pointer Strings
https://elliotsomething.github.io/2016/03/23/iOS-之-基本异常处理/