《Effective Objective-C 2.0编写高质量iOS与OS X代码的52个有效方法》读书笔记(上)

来源:互联网 发布:linux服务总结 编辑:程序博客网 时间:2024/05/07 03:42

1.OC对象所占内存总是分配在"堆"中,而绝不会分配在"栈"中,不能再栈中分配OC对象。"栈"中对象借助栈帧进行维护,"堆"中对象的管理借助引用计数机制.

-(NSMutableArray *)test{    //ary指针本身在栈上,但分配的数组对象在堆上,这也就解释了,为什么函数返回后,ary会随着栈帧弹出而被释放,    //但外部依然能使用NSMutableArray,因为NSMutableArray本身在堆上,依赖引用计数机制进行维护    NSMutableArray *ary = [[NSMutableArray alloc] init];    return ary;}
2.如非必须知道某类的细节,尽量避免头文件的引入,可提高编译效率,降低类之间耦合。尽量把协议单独定义到一个头文件中,同样是为了提高编译效率,减少不必要内容的编译。

3.多用字面量语法

使用字面量语法创建出来的字符串、数组、字典等都是不可变的。若想要可变的,需要mutableCopy一份(要注意深、浅、完全拷贝的概念)。

    NSNumber *num = @1;    NSArray *ary = @[@"1",@"2",@"3"];    NSDictionary *dict = @{@"1":@1,@"2":@2};
4.多用类型常量,少用#define。预处理指令定义的常量不含类型信息,编译器不做检验。

5.多用枚举.(1)表意清晰 (2)按位或(与)操作定义枚举技巧 (3)用NS_ENUM(不需要组合)或NS_OPTIONS(需要组合)来定义枚举,可以确保枚举值的类型 (4)switch枚举值时不要实现default,可借助编译器提示有枚举未处理

6.读取实例变量时尽量采用直接访问,可以绕过方法调用(派发),但不会触发KVO.设置(写)时通过属性进行,使存方法(控制)发挥作用。

7.对象同等性。==判断是指针是否指向了同一对象。

isEqual:建立于hash基础上,isEqual->YES->hash相同;反之hash相同!->isEqual->YES.

isEqual可能包含以下判断:(1).是否本身就是同一对象 (2).是否是同一类对象 (3).各属性(具体判断根据实际需求实现)是否相等 

isEqualToString这类方法相较isEqual,省略了类型的检测,提高了效率

注意isEqual的判定深度

8.工厂模式的使用。+(UIButton)buttonWithType:(UIButtonType)type;

9.SEL又叫选择器,是表示一个方法的selector的指针,仅仅是是函数的标识.(函数名字hash) -> 整数,查询速度快.
   IMP才是函数指针,指向方法实现的首地址.

   method维护SEL与IMP的映射关系。

   objc_msgSend(receiver, selector),objc_msgSend(receiver, selector, arg1, arg2, ...)

   在cache中寻找SEL->在MethodTable寻找SEL。

   _objc_msgForward消息转发做的几件事:
   消息转发:1.动态方法解析 2.备用接收者 3.完整转发
  1. resolveInstanceMethod(resolveClassMethod)+ class_addMethod
  2.forwardingTargetForSelector

  3.forwardInvocation methodSignatureForSelector 如果函数带返回值,则返回最后一个接收者的处理值

  调用methodSignatureForSelector:方法,尝试获得一个方法签名。如果获取不到,则直接调用doesNotRecognizeSelector抛出异常。如果能获取,则返回非nil:创建一个 NSlnvocation 并传给forwardInvocation:。

10.每个对象结构体的首个成员都是Class类的变量(isa),Class结构用于描述对象所属的类。Class对象是单例,每个类的Class仅有一个实例。

     isKindOfClass判断对象是否是某类或其派生类;isMemeberOfClass判断对象是否为某个特定类。

11.提供一个(或多个)全能的初始化方法供其他初始化调用,这样在底层结构发生变化时,只需修改全能初始化方法即可。子类可根据实际需求,适时的覆写超类的全能初始化方法。

12.养成加前缀的习惯避免冲突

13.po打印内容对应debugDescription方法

14.如果某个属性对外只读,对内可读可写,则可在扩展中"重写"@property.

15.异常只应应用于极其严重的错误。

     可以通过在超类方法里抛出异常的方式,要求子类必须覆写超类方法,模拟实现抽象类的效果。

     返回错误时可以借助NSError(domain、code、info)对错误进行描述。

-(BOOL)doSomething:(NSError **)error{    if(/*has error*/){        if (error) {            *error = [NSError errorWithDomain:domain code:code userInfo:info];        }        return NO;    }    else{       return YES;    }}
16.NSZone:以前开发程序时,会把内存分成不同的区,而对象会创建在某个区内。而现在每个程序只有一个默认区。

17.对一不可变对象复制,copy是指针复制和mutableCopy是对象复制。如果是对可变对象复制,都是对象复制,但是copy返回的对象是不可变的。但是collection每个元素都是指针复制,如果相对元素也做到对象复制,可借助-(id)initWithSet:(NSArray *)array copyItems:(BOOL)copyItems类似方法。但如果考虑collection内的元素本身是不可变元素,则还存在trueDeepCopyArray的概念。

18.在使用代理时,在每次调用代理方法时,可能会经常频繁判断代理类是否实现了某代理方法,为了避免多余的检测,可以一上来(比如setDelegate时)判断一次,然后将结果通过自定义的数据结构缓存起来,这样就不用每次去responseToSelector了,提高效率。

19.借助类别将代码(类)模块化,还可实现细节隐藏(可见控制)。

     借助扩展可以实现方法与属性的私有化,隐藏其遵循的协议等。还可在扩展中"重置"属性在内部的读写特性。

20.勿在类别中声明属性。类别本身基于消息机制,动态修改*methodLists的值来添加方法。如果在类别中声明属性,需要自己实现存取方法,进行关联对象,或是返回一个计算属性。

21.id<协议>,协议本身关心的是方法是否被实现(遵循),而不关心对象本身的类型。

0 0
原创粉丝点击