美文网首页ios 程序猿Family《Effective Objective-C 2.0》
《Effective OC》精读笔记(1)—— 熟悉OC

《Effective OC》精读笔记(1)—— 熟悉OC

作者: 笑熬齊澄 | 来源:发表于2017-03-21 17:28 被阅读19次

    第一章:熟悉OC

    第一条:OC是消息型语言,使用“消息结构”而非“函数调用”。

            消息调用与函数的区别:

            1.消息型语言运行时所执行的代码由编译时的环境决定而非编译器,这也就是说运行时才会检查对象类型,也就是我们常说的:runtime 运行时机制

            2.从code中看OC的语法常用方括号:[ ] ,而其他语言多用->。

    第二条:在类的头文件中尽少引用其他头文件。

            创建一个类你需要:

            1.OC使用:头文件(header file)和实现文件(implementation file)来区隔代码。也就是我们常说的.h文件和.m文件,.h文件用于类的声明,而.m文件用于类的实现。

            2.@class和#import的区别:

            #import可以把目标类的全部细节拿出来传给所需文件。

            @class只搞给目标有一个这样的文件,而不知道其细节。(这叫做“向前声明”该类)

            我们一般在.h文件中写@class在.m中使用#import,这样就有效的降低耦合度,避免循环使用。

             无法使用“向前声明”时,比如我们想要某个类遵循一项协议时,我们需要把协议声明放到“class continuation分类”中,如果这样还不行的话,那我们需要把协议放到一个头文件中,然后将其引用。关于“class continuation分类”可以读这篇文章:协议与分类

    第三条:多用字面量语法,少用与之等价的语法。

            OC以语法繁杂而著称,为了真强语法的易读性,我们在编程时间应该尽可能的使用“字面量语法”来避免“alloc”和“init”来为我们分配并初始化内存。什么是“字面量语法呢”,下面我来举一些栗子给大家:

     1.字符串字面量

    NSString * str = [[NSString alloc]initWithString:@"string"];

    NSString * strZML = @"string";

    2.字面量数值

    NSNumber * numInt = [[NSNumber alloc]initWithInt:3];

    NSNumber * numChar = [[NSNumber alloc]initWithChar:'a'];

    NSNumber * numBool = [[NSNumber alloc]initWithBool:YES];

    NSNumber * ZMLnumInt = @1;

    NSNumber * ZMLnumChar = @'a';

    NSNumber * ZMLnumBool = @YES;

    3.字面量数组

    NSArray * arr = [[NSArray alloc]initWithObjects:[NSString stringWithFormat:@"abc"],[[NSNumber alloc]initWithInt:1], nil];

    NSString * str = [arr objectAtIndex:0];

    NSArray * ZMLarr =@[@"abc",@1];

    NSString * ZMLstr = arr[0];

            用initWithObjects处理时,当元素有nil,方法会提前结束。而如果用字面量创建的数组,元素中有nil,则会抛出异常。提高代码的安全性。

            在这个时候,作者提到了“语法糖”这一术语,大概意思是指,在计算机中与另一套语法等效开发者用起来更方便的语法。有兴趣的朋友可以看看这篇文章:[IOS黑魔法] - 语法糖

    4.字面量字典

    NSDictionary * dic = [[NSDictionary alloc]initWithObjectsAndKeys:@"hehe",@"name",[[NSNumber alloc] initWithInt:1],@"age", nil];

    NSDictionary *ZMLdic = @{@"hehe":@"name",@1:@"age"};

           很奇怪,用initWithObjectsAndKeys来创建的字典对象录如数据的顺序是:<对象>,<键>,<对象>,<键>这样的。而用字面量这用@{@“”:@“”},把键映射到对象的格式让人看上去很舒服。

    5.可变对象

           由于字面量创建出来的对象是默认不可变的,如果想要创建可变对象的话也很简单,调用mutableCopy方法即可,如以下code:

    NSMutableString * str = [@"aaaaa" mutableCopy];

    NSMutableArray * arr = [@[@"aaa",@"bbb",@"ccc"] mutableCopy];

    NSMutableDictionary *dic = [@{@"hehe":@"name",@1:@"age"} mutableCopy];

    6.局限性

            除了字符串以外,对象必须是Foundation框架下的才可以。如果是自定义这些类的自类则无法使用字面量!针对这一点作者也给出了解决办法,就是自定义Foundation的子类,但是这样做成本太高,而且比较麻烦,所以并没有建议读者去这么做。

    第四条:多用类型常量,少用#define

             预处理指令:#define 我们可以用它来定义常量,但是有一下两个问题:

            1.用#define创建出来的常量不含有类型信息,编译器只会这编译前据此执行查找与替换这样简单的工作。

             2.用#define创建出来的常量值可以被重新定义,编译器并不会发出相应的警告信息。

             3.常量命名:若常量局限于某个编译单元也就是.m文件中,则在前面加k。若常量在类之外可 见,则通常以类名为前缀。

            综上所诉,作者反对使用#deine来创建常量值,而是建议读者在.m文件中使用 static const 来定义常量,这样做的好处是:

            1.有static的存在,保证了只在编译单元内可见,并不在全局编译表中。

            2.static 与 const 混用编译器会像#define那样将所有出现的变量替换为常值,而且带有类型信息!

            若要在.h文件中定义全局常量,应使用extern来定义。这样当编译器看到.h文件中有extern开头的常量就会明白这个全局变量要放到全局符号表中。注意:为了避免用命重复,使用相关类名做为前缀。

    //定义.h文件中的全局变量

    extern NSString * const VCstring; //指针类型

    extern const NSTimeInterval VClongTime;  //其他类型

    //.m中给其赋值

    NSString * const VCstring = @"ID";

    const NSTimeInterval VClongTime = 30;

            想要详细了解宏定义的童鞋,推荐看喵神写的这篇文章:宏定义的黑魔法 - 宏菜鸟起飞手册

    第五条:用枚举表示状态,选项,状态码

    1.用枚举表示状态

            当程序中需要定义对象的不同状态,我们通常会用一些常量来标记一些东西。这时如果你用一个枚举来表示出来这些状态则会优雅许多。下面我举一个友盟框架中的一个枚举栗子:

    /**QQ消息类型*/

    typedef enum {

    UMSocialQQMessageTypeDefault,    //非纯图片QQ消息

    UMSocialQQMessageTypeImage        //纯图片QQ消息

    }UMSocialQQMessageType;

    可以看到:友盟分享在区分消息类型是纯图片还是非纯图片状态时,就用了枚举值来处理:

    a.用UMSocialQQMessageTypeDefault这一常量来标记了非纯图片QQ消息。

    b.用UMSocialQQMessageTypeImage这一常量来标记了纯图片QQ消息。

    c.用typedef给枚举值取了一个别名:UMSocialQQMessageType来方便调用:

    /**分享到QQ好友的消息类型*/

    @property (nonatomic, assign) UMSocialQQMessageType qqMessageType;


    NS_ENUM: NS_ENUM 的第一个参数是用于存储的新类型的类型。在64位环境下,UITableViewCellStyle 和 NSInteger 一样有8bytes长。你要保证你给出的所有值能被该类型容纳,否则就会产生错误。第二个参数是新类型的名字。大括号里面和以前一样,是你要定义的各种值。

    typedef NS_ENUM(NSInteger, UITableViewCellStyle) {

    UITableViewCellStyleDefault,

    UITableViewCellStyleValue1,

    UITableViewCellStyleValue2,

    UITableViewCellStyleSubtitle

    };


    2.用枚举表示选项

            当我在程序中定义选项时,尤其在定义可以组合的选项时,我们更应该学会枚举去定义你的选项列表,这样可以用“按位或操作符”来去组合你的选项。这些东西常常在许多第三方框架中出现,如果还不了解的同学可以看看这篇文章:枚举值定义选项通过按位或来实现多选,写的挺不错的。好了,接下来让我们看看具体的实现过程,就拿

    相关文章

      网友评论

        本文标题:《Effective OC》精读笔记(1)—— 熟悉OC

        本文链接:https://www.haomeiwen.com/subject/tbawnttx.html