文章目录
  1. 1. 第一章 熟悉我们所使用的Objective-C(以后简称OC)
    1. 1.1. 第1条 了解OC起源
    2. 1.2. 第2条 头文件中尽量少引用其他头文件
    3. 1.3. 第3条 多用字面量,少用与之等价的”方法”
    4. 1.4. 第4条 多用类型常量,少用#define预处理指令
    5. 1.5. 第5条 用枚举表示状态、选项、状态码
  2. 2. 结语

       最近看了几本书,挑了里面几个内容比较好的做了笔记,比较精髓的就分享到博客里面.
       这本是《Effective Objective-C 2.0》,里面的内容非常好,通过分条的形式来总结知识点,这边呢我会时常更新笔记内容.

第一章 熟悉我们所使用的Objective-C(以后简称OC)

第1条 了解OC起源

       首先要了解我们使用的OC语言是消息型语言,知道它是从消息语言的鼻祖Smalltalk语言演化而来的就可以了.这里主要分析一下两种主要类型语言的区别:消息型语言、函数型语言.这里主要区别是:消息型语言,运行时所执行的代码是由运行环境决定的;相对的,函数型语言则由编译器决定.

       在实现多态[^不详解] 时区别比较明显.函数型语言需要借助”虚方法表”[^不详解],而消息型语言不管是不是多态,总是在运行时才查找要执行的方法,这个过程叫”动态绑定”.

       那么OC最重要的组件来了:Runtime component(运行时组件),OC的大部分功能都需要依赖它来实现,这里还有一个相比于函数型语言的优点,就是运行时方式可以只更新运行时组件,不需要重新编译源码,就可以获得程序性能的提升.

       最后一点是OC是C的超集,所有C的功能在OC里面均可用,这里还有一点需要注意的是,其实OC为了性能,并没有将基础数据类型进行对象化,还有像是CGRect和CGSize也是结构体来的,并没有进行对象化,这是合理和需要注意的.

第2条 头文件中尽量少引用其他头文件

       神奇的@class来了~知道为啥要用到@class么?知道.那就略过这一条吧~(你会后悔的)

       @class真正的名字叫做”向前声明”,这样只需要在头文件里@class需要引入的类名,那么编译的时候就不需要直接将引入类的所有实现都编译,相当于告诉编译器,有这么一个文件,并需要编译它,极大的提高了编译速度~也极大的解耦和了~

       另一个,向前声明还解决了另一个问题:互相引用.假设这么个情况,A类需要B类的实现,B类需要A类的实现,两个类都互相需要引入,就会造成循环引用,而用向前引用就可以解决这个问题.对比的@import虽然也可以解决循环引用,但是其实会造成有一个类不能正常编译,可以自己试试看~

       另一个,向前声明并不能对含有协议的类进行向前声明,因为向前声明只是告诉编译器有这么个协议,但是协议本身是需要编译器知道它的方法的.[^这里先知道,后面会有一条详细解释]

第3条 多用字面量,少用与之等价的”方法”

       先来解释一下字面量的含义:字面量是OC的一个语法糖,就是不使用alloc和init[^这里有一个new和alloc区别,回头解释]分配空间初始化的方式,而是类似如下:NSString * str = @"string";直接获取到对象的方式.

使用字面量不仅可以简化语法,OC中基本常用的基础对象都有字面量语法糖.像

1
2
3
4
5
NSNumber * num = @1;
NSNumber * num = @13.1415;
NSNumber * num = @YES;
NSNumber * num = @'a';
NSNumber * num = @(x+y);

就可以极大的简化NSNumber的语法,这也是字面量的一个优点.

       另一个,字面量数组:NSSArray * arr = @[@"sss",@"ddd",@"qqq"];这里还有细微的小差别,就是使用NSSArray * arr = [NSSArray arrayWithObject:obj1,obj2,obj3,niil];和字面量的区别,当obj2为nil时,这种方式创建的数组会发现只含有obj1一个对象,知道为什么嘛?~因为数组创建过程中,会检测是否为nil,如果是nil,就会截止,和字符串的那个结尾检测很类似.而相对的使用字面量来创建的话,就会直接Crash,可以检测数组出现nil空的情况,防止进一步的错误出现,这就是字面量的第二个优点~

       另一个,字面量字典:NSDictionary * dic = @{@"键":@"值",@"键副本":@"值副本"}这就非常符合人的习惯:键:值,而使用方法创建,键值是反的,让人非常不习惯.

       最后一个,字面量这么好是不是可以代替方法了啊?~答案是并非可以.字面量也有自己的局限性:

  • 除了字符串外,字面量创建出来的对象,必须属于Foundation框架才可以,如果自定义了这些类的子类,是不可以使用字面量的,必须使用回初始化方法来创建实例[^不要告诉我你对’实例’这个概念还很模糊哦~],然而一般情况下这些类就已经是基础需求了,不太会自己再继承他们定义新的子类.
  • 字面量创建出来的对象都是不可变的,想要可变,还需要再多调用一层方法哦~不过这么好吃的语法糖~这么点瑕疵,还是非常值得吃的~

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

       首先说明一下#define是从C来的,像我是开始学C入门编程的可能会比较熟悉,像枚举什么的,都是OC从C那里拿来的.这里还要再留一个稍后解释的点.[^了解typedef NS_OPTIONStypedef NS_ENUM么~嘿嘿稍后解释~HD]

       其实个人非常喜欢预处理指令,因为他可以将你后期可能需要修改的参数独立出来,甚至可以都放到一起,放到pch头文件里,这个在集成接口文档、系统级别常参的时候非常好用,但是这样写出的代码耦合性非常高,非常不容易模块化,不过方便大于缺点~哈哈哈哈~

       回归正题,既然说到了多用类型常量,那就先来看看类型常量:static const NSTimeinterval kAnimationDuration = 0.3;这下知道是啥了吧,其实就是定义全局参数,这样比较好的地方是可以知道定义的参数的类型,还有就是编纂开发文档的时候也非常的方便易读.这里有个小Tip:一般来说,一般类内定义开头以k命名,类外以类名为前缀.这个后面的条目里面会有更加详细的命名规范的解释.

       下面就来解释解释大家肯定比较关心的问题 staticconst啥意思啊?干啥的啊?其实说到底都是C的API,简单点来解释呢就是:const修饰的是编译器级别的死值,如果你敢妄动,那就给你报错!而static修饰呢,说明该变量是隐私的,只有定义这个变量的编译单元可以使用,别问我啥是编译单元,我会杀人的…

       而有时候呢我又想放一个别类也能用的参数怎么办?可以办,把static改成extern,这样在其他的类中就可以取到了,这个在发通知的时候用来做”注册类型”比较好使,其实就像是定义一个枚举给它类用一样的意思.

       这里还有一个Tip: NSString const * strNSString * const str的区别还记得么?想一想~

       跑偏了,回来回来继续说明为啥少用预处理,多用类型常量,因为预处理可能会被无意中篡改,和你本来希望用的是不一样的,结果就黑了.

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

       还记得之前留下的小Tip么?~typedef NS_OPTIONStypedef NS_ENUM现在就来解决这个HD.怎么说呢,其实enum是除了预定义以外,我最喜欢从C那儿拿来用的语法,只能说不用不知道,用的偷偷笑~

       本来呢enum是需要这么定义的enum AnimationType type = AnimationTypeFromTop,很麻烦吼,但是呢咖啡有伴侣,enum有typedef~通过typedef这么一幻化,叮~

1
2
3
4
5
6
enum AnimationType{
AnimationTop,
AnimationLeft,
AnimationRight,
};
typedef enum AnimationType AnimatioTYpoe;

好的,接下来我们就可以这样定义枚举类型了:AnimationTYpe animationType,是不是方便又简洁,但是要注意我写的示例代码细节哦~其实呢,系统有一个定义enum的超级快速方法:在需要定义enum的地方,键入eunm,回车就搞定一个简易的Enum,

1
2
3
4
5
typedef enum : NSUInteger {
<#MyEnumValueA#>,
<#MyEnumValueB#>,
<#MyEnumValueC#>,
} <#MyEnum#>;

然后就可以使用啦~咋使用?我要杀人…好吧,可以把他当做是类属性,可以把它定义到接口中当参数……很多很多,常用就好~

       下面说点有意思的,自从C++11定制以来,不要问我啥是C++11,也不要问我为啥C++的标准OC也能受益,请允许我杀人…OC的enum可以定义枚举的”底层保存类型”,不单单只可以用NSInteger哦!不过平常也不太会用到这个,知道有这么一个情况就好了.

       下面说说重点,就是typedef NS_OPTIONStypedef NS_ENUM这两个宏的区别以及用处.其实枚举是系统级别API极为常用一个语法,可以说随时可见,举个栗子:

  • typedef NS_ENUM是普通的枚举类型的定义,就是用来表示各种不同的状态的,而这些状态都是互斥的,何为互斥呢,就是有A,就不会用B.这个很容易理解.
  • typedef NS_OPTIONS则是”选项枚举”,如上图所示的OPTIONS枚举值,其实是通过位运算得到的,既然利用了位运算,那么就有一个好处了,就是可以利用”按位或操作”来组合需要的枚举值,不再是只能单一使用某一个枚举值,并且得到的枚举值,不会出现重复的情况.这个是系统极为常用的一个语法糖,可见它的好用以及重要之处.还有就是上面也说过了这两个定义其实就是两个宏,知道这个概念就行.
  • 最后一个重点,就是不管是用上面哪种,最后大多会配合Switch语句进行判断使用,那么这时候Switch语句最好不要带default语句,因为你的枚举类型是可扩展的,不一定稳定,当你需要为你的枚举添加新的值得时候,如果没有switch的default语句,那么就会报错,这样呢就可以提醒你你还有事情要做,如果带着default,它就会默认处理掉,这可能会给你的代码带来灾难性的后果.所以这一点要谨记枚举的switch不带default!

结语

       最后来个总结吧,就是开发这个东西吧跟别的行业不太一样,想要有所建树,那就不光要知其然,还应该要培养自己知其所以然的习惯,因为只是用的话,随便一个初中生都能比你用得好,所以想让自己有朝一日成为高级工程师,或者以后去到其他开发行业,哪怕甚至不在编程行业了,能够拥有这种习惯对于自己都是非常受益的!看了一下时间两点四十了,该睡觉了~下次分享见~

文章目录
  1. 1. 第一章 熟悉我们所使用的Objective-C(以后简称OC)
    1. 1.1. 第1条 了解OC起源
    2. 1.2. 第2条 头文件中尽量少引用其他头文件
    3. 1.3. 第3条 多用字面量,少用与之等价的”方法”
    4. 1.4. 第4条 多用类型常量,少用#define预处理指令
    5. 1.5. 第5条 用枚举表示状态、选项、状态码
  2. 2. 结语