Effective Objective-C 2.0
===
第52条 NSTimer引用
- 使用block语法代替iOS10支持
- iOS10以前
@implementation NSTimer
+(NSTimer *)ll_scheduledTimerWithTimeInterval:(NSTimeInterval)ti
block:(void (^)())block
repeats:(BOOL)yesOrNo{
[self scheduledTimerWithTimeInterval:ti
target:self
selector:@selector(ll_timerblock:)
userInfo:[block copy]
repeats:(BOOL)yesOrNo];
}
+(NSTimer *)ll_timerblock:(NSTimer*)timer {
void (^block)() = if(timer.userInfo);
if(block){
block();
}
}
@end
第51条 +load和+initialize
+load | +initialize | |
---|---|---|
运行时机 | 程序启动时 | 第一次调用时 |
调用父类 | �子类不实现+load不会调用父类+load | 子类不实现会调用父类+initialize |
分类 | 分类实现了+load先调基类,再调分类 | 子类实现了+initialize,先调超类,再调自身,通常要判断类型是否等于自身 |
实际应用 | 方法交换 | 初始化编译时不能确定的全局变量如NSMutableArray,或者单例模式使用前执行必要的初始化动作。 |
注意事项
- initialize运行时线程安全,运行线程不确定。
- 尽量避免在两种方法里面执行耗时操作
— 尽量避免在两种方法里面调用其他类或方法,有可能会出现互相依赖导致未能正确初始化的情况。
第50条 构建缓存时选用NSCache而非NSDictionary
NSCache | NSDictionary | |
---|---|---|
自动删除 | Y (LRU) | N |
拷贝Key | N | Y |
线程安全 | Y | N |
第49条 对自定义其内存管理语义的 collection 使用无缝桥接
- 代码演示
NSArray *anNSArray = @[@1,@2,@3,@4,@5];
CFArrayRef aCFArray = (__bridge CFArrayRef)anNSArray;
NSLog(@"Size of array = %li",CFArrayGetCount(aCFArray));
//Output: Size of array = 5
__bridge | 保留ARC所有权 |
__bridge_retained | 交出ARC所有权 |
__bridge_transfer | CF对象转OC对象所有权交给ARC |
- 例如使用CFMutableDictionary创建出保留key的Dictionary
第48条 多用块枚举,少用for循环
- Objective-C 1.0反向枚举器
NSArray *anArray = /* ... */;
NSEnumerator *enumerator = [anArray reverseObjectEnumerator];
id object;
while((object = [enumerator nextObject]) != nil) {
//do something with 'object'
}
- 快速遍历
NSArray *anArray = /*...*/;
for (id object in anArray) {
//do something with 'object'
}
- 自定义快速遍历需要�NSFastEnumeration协议
//实现协议方法
- (NSUInteger) countByEnumeratingWithState:(NSFastEnumerationState*)state
objects:(id*)stackbuffer
count:(NSUInteger)length
- Objective-C 2.0快速反向遍历
缺点:拿不到下标
NSArray *anArray = /*...*/;
for (id object in [anArray reverseObjectEnumerator]) {
//do something with 'object'
}
- 基于块的遍历方式
NSArray *anArray = /*...*/;
[anArray enumerateObjectsUsingBlock:
^(id object, NSUInteger idx, BOOL *stop){
//do something with 'object'
if(shouldStop) {
*stop = YES;
}
}];
- 可以使用NSEnumerationOptions类型
NSEnumerationReverse 反向遍历
NSEnumerationConcurrent 并发遍历
第47条 熟悉系统框架
NSLinguisticTagger 解析字符串并找到其中的全部名词,动词,代词
CFNetwork C语言网络通信框架
CoreAudio C语言Api操作设备伤的音频硬件框架
AVFoundation 回放并录制音频视频
CoreData Objective-C对象持久化框架
CoreText C语言接口文字排版及渲染
第46条 不要使用 dispatch_get_current_queue
- 该函数用来获取当前的队列,已经标记废弃。
- 使用dispatch_get_current_queue依然会死锁的例子
dispatch_sync(queueA, ^{
dispatch_sync(queueB,^{
dispatch_block_t block = ^{/*....*/};
if(dispatch_get_current_queue() == queueA) {
block();
} else {
dispatch_sync(queueA, block);
}
});
});
//解决方法,使用dispatch_get_specific来替换上面这种写法
- GCD派发层级
全局并发队列
/ \
串行队列A 串行队列D
/ \
串行队列A 串行队列D
串行队列B,C的任务有可能放到队列A中交替执行
串行队列A,D的目标是并发队列,A,D中的块会并发执行