Effective Objective-C 2.0编写高质量iO

2018-06-15  本文已影响42人  JonorZhang

2017/12/31


第一章 熟悉Objective-C

第1条 了解Objective-C语言的起源

第2条 在类的头文件中尽量少引入其他头文件

第3条 多用字面量语法

第4条 多用类型常量,少用#define预处理指令

第5条 用枚举表示状态、选项、状态码

第二章 对象、消息、运行期

第6条 理解“属性”这一概念

第7条 在对象内部尽量直接访问实例变量

第8条 理解“对象等同性”这一概念

第9条 以“类族模式”隐藏实现细节

第10条 在既有类中使用关联对象存放自定义数据

void setAssociatedObject(id object, void\*key, id value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, void\*key);
void objc_removeAssociatedObjects(id object)

第11条 理解objc_msgSend的作用

第12条 理解消息转发机制

第13条 用“方法调配技术”调试“黑盒方法”

第14条 理解“类对象”的用意

第三章 接口与API

第15条 用前缀避免命名冲突

第16条 提供“全能初始化方法”

第17条 实现description方法

第18条 尽量使用不可变对象

// Person.h
@interface Person:NSObject
@property (nonatomic, strong, readonly) NSSet *friends;
@end

// Person.m
@implementation Person {
    NSMutableSet *_internalFriends;
}

- (NSSet *)friends {
    return [_internalFriends copy];
}
- (void)addFriend:(Person *)person {
    [_internalFriends addObject:person];
}
@end

第19条 使用清晰而协调的命名方式

第20条 为私有方法名加前缀

第21条 理解Objective-C错误模型

第22条 理解NSCopying协议

第四章 协议与分类

第23条 通过代理与数据源协议进行对象间通信

// 如果频繁调用如下代码:
if ([_delegate respondsToSelecter:@selecter(someClassDidSomething:)]) {
    [_delegate someClassDidSomething];
}
// 可考虑将检查加过缓存到本地标记:
_delegateFlags.didUpdateProgressTo = [_delegate respondsToSelecter:@selecter(someClassDidSomething:)]
...
if (_delegateFlags.didUpdateProgressTo) {
    [_delegate didUpdateProgressTo:progress]
}

第24条 将类的实现代码分散到便于管理的数个分类之中

第25条 总是为第三方类的分类名称加入前缀

第26条 勿在分类中声明属性

第27条 使用匿名扩展隐藏实现细节

第28条 通过协议提供匿名对象

第5章 内存管理

第29条 理解引用计数

第30条 以ARC简化引用计数

第31条 在dealloc方法中只释放引用并解除监听

第32条 编写“异常安全代码”时留意内存管理问题

第33条 以弱引用避免保留环

第34条 以“自动释放池”降低内存峰值

@autoreleasepool {
    // ...
}

第35条 用“僵尸对象”调试内存管理问题

第36条 不要使用retainCount

块与大中枢派发

第37条 理解“块”这一概念

// 不安全的块,因为A块、B块都是分配在栈上的,离开了if语句可能会被释放
void (^block)();
if (condition_1) {
    block = ^{ print("A") };
} else {
    block = ^{ print("B") };
}
block();

// 若将块拷贝copy就会搬到堆上,就会变成对象,就会安全
block = [^{ print("A") } copy];
block = [^{ print("B") } copy];

第38条 为常见的块类型创建typedef

第39条 用handler块降低代码分散程度

第40条 用块引用其所属对象时不要出现保留环

第41条 多用派发队列,少用同步锁

// 1. synchronized
@synchronized(self) {
    return _someString;
}
// 2. nslock
NSLock *_locker = [[NSLock alloc] init];
[_locker lock];
// safe code
[_locker unlock];
_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//读取字符串
- (NSString *)someString {
    __block NSString *localSomeString;
     dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });
     return localSomeString;
}
- (void)setSomeString:(NSString*)someString {
     dispatch_barrier_async(_syncQueue, ^{
        _someString = someString;
    });
}

第42条 多用GCD,少用performSelector系列方法

第43条 掌握GCD以及操作队列的使用时机

第44条 通过Dispatch Group机制,根据系统资源状况来执行任务

// A B C将会同步执行
dispatch_group_async({...A})
dispatch_group_async({...B})
dispatch_group_async({...C})
// 以上都执行完再执行notify
dispatch_group_notify({...})

第45条 使用dispatch_once来执行只需要运行一次的线程安全代码

+ (instancetype)sharedInstance {
    static id _instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone: NULL] init];
    });
    return _instance;
}

+ (id)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

- (id)copyWithZone:(struct _NSZone *)zone {
    return [[self class] sharedInstance];
}

- (instancetype)init {
    if (self = [super init]) {
        <#code#>
    }
    return self;
}

第46条 不要使用dispatch_get_current_queue

第7章 系统框架

第47条 熟悉系统框架

第48条 多用块枚举,少用for循环

[dict enumeratKeysAndObjectsUsingBlock: ^(NSString \*key, NSString \*obj){
    // ...
}];

第49条 对自定义其内存管理语义的collecion使用无缝桥接

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如何处理转换所涉及的OC对象,也就是ARC仍然具备这个OC对象的所有权。__bridge_retained则意味着ARC将交出所有权。

第50条 构建缓存时选用NSCache而非NSDictionary

第51条 精简initialize与load的实现代码

第52条 别忘了NSTimer会保留其目标对象

上一篇 下一篇

猜你喜欢

热点阅读