Effective Objective-C学习笔记

  1. 所有OC对象总是分配在堆空间中,而不是分配在栈上。不能在栈中分配OC对象。
  2. 如果someString变量指向分配在堆里的某个内存,其中含有一个NSString对象,如果再创建一个变量,令其指向同一地址,那么不会拷贝该对象,只是这两个变量会同时指向此对象。
  3. 分配在堆中的内存必须直接管理,分配在栈上用于保存变量的内存则会在其栈帧弹出时自动清理。
  4. OC的运行时环境把堆内存管理这部分工作抽象为一套内存管理架构,叫做“引用计数”。
  5. 有时候会遇到定义里不含*的变量,他们可能会使用“栈空间”。这些变量保存的不是OC对象。eg:CoreGraphics框架中的CGRect就是个例子。
  6. 相对于创建结构体,创建对象需要额外的开销,比如分配及释放内存等。如果只需要保存int,float,double,char等非对象类型,通常使用结构体就可以。
  7. OC使用动态绑定的消息结构,在运行时才会检查对象类型。在接收一条消息后,究竟应该执行何种代码,由运行时环境而不是编译器决定。
  8. 在类的头文件中尽量少引入其他头文件。在头文件中不需要知道引入的其他类的全部细节,只需要知道有一个类名就可以,使用@class指令。

    eg. @class Employer
    

    这叫做“向前声明”该类。

    而在实现文件中,则需要引入Employer类的头文件,因为需要知道其所有接口的细节。
    使用#import “”指令。

  9. 将引入头文件的时机尽量延后,只在却有需要时才引入,这样就可以减少类的使用者所需要引入头文件的数量。

  10. 向前声明也解决了两个类互相引用的问题。如果在两个类各自的头文件中引入对方的头文件,会导致循环引用。
  11. 有时必须要在头文件中引入其他文件。
    • 如果你写的类继承自某个超类,则必须引入定义那个超类的头文件。
    • 如果要声明你写的类遵从某个协议,那么该协议必须有完整的定义,且不能使用向前声明。只能使用#import指令。向前声明只能告诉编译器有某个协议,而此时编译器却要知道该协议中定义的方法。
  12. 最好讲协议单独放在一个头文件中。但是有些协议,比如委托协议就不用单独写一个头文件了。在这种情况下,协议只有与接受协议委托的类放在一起定义才有意义。此时最好能在实现文件中声明此类实现了该委托协议,病啊这段代码放在“class-continuation分类里”。这样,只要在实现文件中引入包含委托协议的头文件即可,而不需要将其放在公共头文件里。
  13. 多用字面量语法,少用与之等价的方法。
  14. 当需要报整数,浮点数,布尔值封装进OC对象中,可以使用NSNumber类。
  15. 字面量语法也适用于下面的表达式。

    int x = 5;
    float y = 6.32f;
    NSNumner *expressionNumber = @(x+y);
    
  16. 用字面量语法创建数组时要注意,若数组元素中有nil时,会抛出异常,因为字面量语法实际上只是一种“语法糖”,其效果等于是先创建了一个数组,然后把方括号中的所有对象那都加到这个数组中。

  17. NSArray *arrayA = [NSArray arrayWithObjects:object1,object2,object3];
    NSArray *arrayB = @[object1,object2,object3];
    如果object1和object3都指向了有效的OC对象,而object2是nil,则按字面量语法创建数组arrayB时会抛出异常。而arrayA虽然能创建出来,但是其中却只包含一个object1对象,原因在于,“arrayWithObjects”方法会一次处理各个参数,直到发现nil为止,因为object2是nil,所以该方法会提前终止。所以使用字面量语法会更为安全。
  18. 字面量语法有个小小的缺点,就是除了字符串以外,所创建出来的对象必须属于Foundation框架才行。
  19. 通过字面量创建出来的字符串,数组,字典都是不可变的。若想要可变版本的对象,则需要复制一份:用mutableCopy方法。这样会多调用一个方法,而且还需要再创建一个对象,不过使用字面量语法所带来的好处是多于以上缺点的。
  20. 多用类型常量,少用#define预处理指令。
  21. 有个方法比预处理指令来定义常量更好。

    eg:static const NSTimeInterval kAnimationDuration = 0.3;
    

    此种方式定义的常量包含类型信息,其好处是清楚地面熟了常量的含义。

  22. 另外还要注意常量的名称。通常的命名法是:若常量局限于某个“编译单元”(也就是实现文件)之内,则在前面加字母k;若常量在类之外可见,则通常以类名为前缀。
  23. 如果不打算公开某个常量,则应该将其定义在使用该常量的实现文件里。变量一定要同时用static与const来声明。如果试图修改由const修饰符所声明的变量,那么编译器就会报错。而static修饰符则意味着该变量仅在定义次变量的编译单元中可见。假如声明此变量时不加static,则编译器会为它常见一个“外部符号”。若是另一个编译单元中也声明了同名变量,那么编译器就会抛出错误消息:

        duplicate symbol _kAnimationDuration in:
                EOCAnimationedView.o
                EOCOtherView.o
    
  24. 实际上,如果一个变量既声明为static,又声明为const,那么编译器根本不会创建符号,而是会像#define预处理指令一样,把所有遇到的变量都替换为常值。不过还是要记住,用这种方式定义的常量带有类型信息。
  25. 如果需要对外公开某个常量,此类常量需要放在“全局符号表”中,以便可以在定义该变量的编译单元之外使用。其定义方法如下:

    //  在头文件中
    extern NSString *const EOCStringConstant;
    
    //  在实现文件中
    NSString *const EOCStringConstant = @“VALUE”;
    

    这个常量在头文件中声明,在实现文件中“定义”。
    编译器看见头文件中extern关键字,就知道如何让在引入此头文件的代码中处理该常量了。
    extern关键字告诉编译器,在全局符号表中将会有一个叫做EOCStringConstant的符号。也就是说,编译器无需查看其定义,即允许代码使用此常量。因为它知道,当链接称为二进制文件之后,肯定能找到这个常量。
    此类常量必须要定义,而且只能定义一次。通常将其定义在与声明该常量的头文件相关的实现文件中。由实现文件生成目标文件时,编译器会在“数据段”(data section)为字符创分配储存空间。连接器会将此目标文件与其他目标文件相连接,已生成最终的二进制文件。凡使用到EOCStringConstant这个全局符号的地方,链接器都能将其解析。

  26. 为避免名称冲突,最好是用与之相关的类名做前缀。

  27. 常量定义应该从右向左解读,比如25中的EOCStringConstant就是“一个常量,而这个常量是指针,指向NSString对象”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值