本次博客撰写小蓝书的最后一章系统框架
OC的Foundation框架,像NSObject NSArray, NSDictionary等类都在其中。Foundation框架里的类都是用NS前缀,因为OC之前作为NeXTSTEP操作系统确定的。
将一系列代码封装为动态库,并在其中放入描述其接口的头文件,这样做出来的东西就叫框架。
CoreFoundation框架
Foundation框架提供了collection等基础核心功能,而且还提供了字符串处理等复杂功能。还存在一个CoreFoundation框架,在之前了解过他是不属于OC框架之内的,但是OC应用程序的编写离不开这个框架,Foundation框架的许多功在CoreFoundation框架都可以找到对应的C语言API
他其中的很多类都和Foundation框架相似,并且我们还可以通过“无缝桥接”功能实现CoreFoundation框架中的C语言数据结构平滑转换为Foundation框架中的OC对象,也可以反向转换。无缝桥接技术是用某些相当复杂的代码实现出来的,这些代码可以使运行期系统把CoreFoundation框架中的对象视为普通的OC对象。
NSString所对应的就是CFString对象。
其他框架:
OC编程的重要特点就是:经常需要使用底层的C语言级 API。用c语言实现 API的好处是,可以统过 Objeotive-C 的运行期系统,从而提升执行速度
要点
语言中引人“块” 这一特性后,又多出来儿种新的通历方 式,而这几种方式容易为开发者所忽视。采用这几种新方式遍历collection 时,可以传人块, 而collection 中的每个元素都可能会放在块里运行一遍,这种做法通常会大幅度简化编码过程以下进行各种遍历方法详细说明:
for循环
根据定义,因为字典与set对象是无需的,所以无法通过下标访问,所以需要先获取字典里的所有键值或是set中的所有对象,这两种情况下都可以放到数组中实现,就如上述代码所显示
NSEnumerator遍历
NSEnumerator是个抽象基类,其中只定义了两个方法,供其具体子类来实现:
关键的是其中的nextObject对象,它返回枚举里的下个对象,当返回不为nil的时候就会一直调用下一个对象,常用while语句
对于set与字典写法其实也与标准的for循环相似,只是代码多了一些,其优势在于无论遍历哪一种collection,都可以采用这套相似的语法
快速遍历
快速遍历是OC2.0引入的语法功能,引入了in关键字,语法更加简洁了collection的遍历过程。尤其是字典类
基于块的遍历方式
参数1是每次枚举的对象, idx是下标, stop则是代表是否停止遍历
使用这种方法遍历时既能获取对象,也能知道其下标
[t enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"%@ %lu", obj, (unsigned long)idx);
}];
此方式大大胜; 过其他 方式的地方在于:遍历时可以直接从块里获取更多信息。在遍历数 组时,可以知道当前所针对的下标。遍历有序set (
NSOrderedset )时也一样。而在遍历字典 时, 无须额外编码,即可同时获取键与值,因而省去了根据给定键来获取对应值这一步。用
这种方式遍历字典,可以同时得知键与值,这很可能比其他方式快很多,因为在字典内部的 数据结构中,键与值本来就是存储在一起的。
要点
Objective-C的系统库包含相当多的collection 类,其中有各种数组、各种字典、各种 setoFoundation框架定义了这些collection及其他各种collection所对应的Objective-C类 。与 之相似,CoreFoundation 框架也定义了一套C语言API,用于操作表示这些collection 及其他 各种collection 的数据结构。
例如,NSAray 是Foundation 框架中表示数组的Objective-C类, 而CFArray 则是CoreFoundation 框架中的等价物。这两种创建数组的方式也许有区别,然而 有 项 强 大 的 功 能 可 在 这 两 个 类 型 之 间 平 滑 转 换, 它 就 是 “ 无 缝 桥 接” ( t o l l - f r e e b r i d g i n g ) 。
转换操作中的__bridge
告诉ARC如何处理转换所涉及的OC对象。__bridge
本身的意思是:ARC仍然具备这个OC对象的所有权。而__bridge_retained
则与之相反,意味着ARC将交出对象的所有权。与之相似,反向转换可通过__bridge_transfer
来实现,也就是将对象的所有权交给ARC。这三种转换方式称为“桥式转换”
- (void)seamlessBridging {
NSArray *testArray = @[@"111", @"222", @"333",];
CFArrayRef aCFArray = (__bridge CFArrayRef)testArray;
NSLog(@"cfArratSize = %li", CFArrayGetCount(aCFArray));
}
要点
开 发 M a c O s × 或 i 0 s 应 用 程 序 时 , 经 常 会 遇 到 一个 问 题 , 那 就 是 从 因 特 网 下 载 的 图 片 应如何来缓存。首先能想到的好办法就是把内存中的图片保存到字典里,这样的话,稍后使 用 时 就 无 须 再 次 下 载 了。 有 些 程 序 员 会 不 假 思 索 , 直 接 使 用 N S D i c t i o n a r y 来 做 (准 确 来 说 , 是使用其可变版本),因为这个类很常用。其实,NSCache 类更好,它是Foundation 框架专 为处理这种任务而设计的。
NSCache 胜过NSDictionary 之处在于,当系统资源將要耗尽时,它可以自动删减缓存。
另外,NSCache 是线程安全的。 而NSDictionary 则绝对不具备此优势
要点
在OC里一个类必须初始化才能使用,大多数类继承与NSObject这个根类,提供了load
和initalize
方法
load
加入运行期系统中的每个类和分类来说,会调用此方且仅调用一次,当类和分类的程序载入系统的时候就会执行这个方法,调用顺序是类大于分类。
总结一句话就是不要用load
initalize
该方法是在程序首次使用该类之前调用且仅有一次,是由运行期系统调用的,不通过代码调用。和load存在区别
initalize方法尽量精简
initalize方法只应该用来设置内部数据,不能在内部调用其他的方法。
initalize还可以初始化某个无法在编译器初始化的全局变量
但别忘了单例类也可以实现该目的
要点
Foundation框架中有个类叫NSTimer,开发者可以指定绝对的日期与时间,以便到时执行任务,计时器要和“运行循环(run loop)”相关联,运行循环到时候会触发任务。创建NSTimer时,可以将其“预先安排”在当前的运行循环中,也可以先创建好,然后由开发者自己来调度。无论采用哪种方式,只有把计时器放在运行环里,它才能正常触发任务
创建计时器
_pollTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(pDoPoll) userInfo:nil repeats:YES];
保留环
创建计时器的时候,由于目标对象是self,所以要保留此实例。然而,因为计时器是用实例变量存放的,所以实例也保留了计时器,于是,就产生了保留环。所以说,调用stopPolling,或者令系统将此实例回收,只有这样才能打破保留环。
因为是类和这个类中的实例出现了保留环,不管你外界怎么对这个类释放,这个计时器始终都会保留这个类,而这个类也会保留这个计时器,互相引用保留导致他们的计数永远都不会降为0
使用块的特点打破保留环
使用块和weak关键字合理的打破保留环,块可以传递代码,这一功能可以利用
这个办法为何能解快“ 保留环〞问题呢?大家马上就会明白。这段代码将计时器所应执 行的任务封装成“ 块”,在调用计时器西数时,把它作为userlnfo 参数传进去。该参数可用来 存 放 “ 不 透 明 值 ” ( o p a q u e v a l u e )。 , 只 要 计 时 器 还 有 效 , 就 会 一直 保 留 着 它 。 传 人 参 数 时 要 通 过copy方法将block拷贝到“堆” 上(之前在blk提过,copy方法把块变成了有引用计数的对象。),否则等到稍后要执行它的时候,该块 可能己经无效了。计时器现在的target 是NSTimer 类对象,这是个单例,因此计时器是否会 保 留 它, 其 实 都 无 所 谓 。 此 处 依 然 有 保 留 环 , 然 而 因 为 类 对 象 ( c l a s s o b j e c t ) 无 须 回 收 , 所 以 不用担心。
此处依然有保留环,使用weak关键字打破它
这 段 代 码 采 用 了一 种 很 有 效 的 写 法 , 它 先 定 义 了一 个 弱 引 用 , 令 其 指 向 s e l f , 然 后 使 块 捕获这个引用,而不直接去捕获普通的sel f 变量。也就是说,sel f 不会为计时器所保留。当 块开始执行时,立刻生成strong 引用,以保证实例在执行期间特续存活。
采用这种写法之后,如果外界指向EOCClass实例的最后 一个引用将其释放,则该实例 就 可 为 系 统 所 回 收 了。
要点