iOS-Effective Objective-C 2.0 读书笔记(一)

今天开始看了Effective Objective-C 2.0的一部分内容,然后打算记录下来一些其中提到的比较有用的注意点,然后在之后的实际开发过程中能有所规避,写出更好的代码。

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

  一般我们在开发过程中编写一个类时候会分别创建.h.m两个文件。而且大部分情况下我们创建的类和类之间会有关联,比如说类A中包含了一个类B类型的属性,那么在类A的实现文件中则会需要引入类B的头文件。那么问题来了,在什么地方引入类B的头文件呢?
  最直接的方式就是在类A的.h文件中import类B的头文件了,然而这种方式虽然可行,但是并不够优雅。因为在.h文件中,不需要知道某个类的全部具体实现,只需要知道一个类名叫什么就好了。所以通常情况下我们都会在类A中通过以下方式告诉编译器存在一个类B。这种方式又被成为“向前声明”该类(这种方式可以降低类之间的耦合度?)。

//myClassA.h
@class myClassB;

  然后在具体的类A的.m文件中才真正的引入类B的头文件。因为在实现文件时候类A才会真正依赖于类B的具体实现,需要知道其相关接口信息。

//myClassA.m
import "myClassB.h"

  通过这种方式,将引入头文件的时机尽量延后,只需要在确需要的时候才引入,这样可以减少类的使用者所需要引入的头文件的数量。

  此外,向前声明也可以解决两个类互相引用的问题。如果类A引用了类B,类B又引用了类A,那么在解析A的头文件时需要引入另一个头文件,而恰巧另一个头文件也需要引用A,所以就会造成“循环引用”的情况。所以当使用#include而不是使用#import方式引入头文件时,则会导致死循环。

  在实际情况中,有时候不可避免的必须要在头文件中引入其他头文件。比如说写的类需要遵循某个协议的时候,那么这个协议必须要有完整的定义,且不能使用向前声明。所以这种类型的协议一般都单独写在一个头文件里。

  而像“委托协议”这样的则不需要单独写一个头文件,因为其通常只有与接收协议委托的类放在一起时候才有意义。

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

首先我们先来列举一下使用#define的不好的地方。

  1. 定义出来的常量没有类型信息。
  2. 编译器会简单的把引入该宏的所在头文件的地方,将所有的宏替换为定义的值,可能会导致代码膨胀。
  3. 错误的宏定义可能会导致错误。例如宏定义的式子里要注意使用括号括起来,不然可能会导致一些计算式子的计算顺序出错。

所以作者推崇的方式是使用定义常量代替宏定义。

static const NSString *MyClassAVar = @"hello world."; 

  使用此方法的优点就在于常量包含类型信息,可以清楚描述常量的含义。但是实际开发中需要注意常量命名规范,若常量局限于某“编译单元”(也就是局限在“实现文件”内),则在前面加字幕k;若常量在类之外可见,则通常以类名为前缀。

  此外,无论使用宏定义还是使用常量定义,都需要注意的一点就是如果把该定义放在了头文件里,就要小心变量名冲突的问题。所以如果可以的话,推荐采用常量定义的方式,并且对于一些没必要对外访问的常量定义在实现文件中。而对于那些对外的常量定义,则需要比较规范的变量命名了避免命名冲突的问题,一般此类变量写法如下:

//在头文件中,创建的是指针常量,说明不能改变该指针变量指向的对象地址。
extern NSString *const LYSStringConstant;

//在实现文件中
NSString *const LYSStringConstant = @"com.lysongzi.value";

  并且以上变量必须要定义,且只能定义一次。通常都是将其定义在与声明该变量的头文件相关的实现文件里。由实现文件生成目标文件时,编译器会在“数据段”为字符串分配存储空间。链接器会把此目标文件与其他目标文件相链接,已生成最终的二进制文件。

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

  枚举是一种常量命名方式。某个对象的各种状态我们都可以定义为一个简单的枚举集。并且在C++11标准之后扩充了枚举的一些特性,这些都使得枚举用来状态集是一种非常好的方式。通常情况下还会结合typedef这个关键字一起定义枚举类型。其中枚举类型主要有下面几种用法。

1.1 表示状态集合

//默认情况下的话编译器会给个枚举分派一个编号,从0开始,每个枚举递增1
typedef enum LYSConnectionState{
    LYSConnectionStateConnected, //0
    LYSConnectionStateConnecting, //1
    LYSConnectionStateDisconnected //2
};

//当然还可以手工指定某个枚举成员的对应值
typedef enum LYSConnectionState{
    LYSConnectionStateConnected = 1,
    LYSConnectionStateConnecting = 2, 
    LYSConnectionStateDisconnected //3
};

然后这样使用。

LYSConnectionState state = LYSConnectionConnected;

1.2 表示选项集合

typedef enum UIViewAutoresizing{
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexbleLeftMargin    = 1 << 0,
    UIViewAutoresizingFlexbleRightMargin   = 1 << 1,
    UIViewAutoresizingFlexbleTopMargin     = 1 << 2,
    UIViewAutoresizingFlexbleBottomMargin  = 1 << 3,
};

每个选项都可以开启或关闭,使用上述方式定义枚举值可以结合“按位或操作符”来组合开启某个选项。用法如下:

UIViewAutoresizing resizing 
    = UIViewAutoresizingFlexbleLeftMargin | UIViewAutoresizingFlexbleRightMargin;

//然后判断某个值是否开启了某个选项时使用与操作
if(resizing & UIViewAutoresizingFlexbleLeftMargin) {...}
else if(resizing & UIViewAutoresizingFlexbleRightMargin) {...}

1.3 进阶

c++11标准修订了枚举的某些特性。是的枚举可以致命用何种“底层数据类型”来保存枚举类型的变量。比如上述中的LYSConnectionState类型枚举可以写成如下格式:

typedef enum LYSConnectionState : NSInteger {
    LYSConnectionStateConnected, //0
    LYSConnectionStateConnecting, //1
    LYSConnectionStateDisconnected //2
};

再者,Foundation框架中定义了一些辅助的宏,以方便我们定义枚举类型时,也可以指定用于保存枚举类型值的底层数据类型。比如以下写法:

typedef NS_ENUM(NSUInteger, LYSConnectionState) {
    LYSConnectionStateConnected,
    LYSConnectionStateConnecting,
    LYSConnectionStateDisconnected
};

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexbleLeftMargin    = 1 << 0,
    UIViewAutoresizingFlexbleRightMargin   = 1 << 1,
    UIViewAutoresizingFlexbleTopMargin     = 1 << 2,
    UIViewAutoresizingFlexbleBottomMargin  = 1 << 3,
};

其中我们可以看一些这些宏中核心部分是怎么写的。当然这里是针对OC的写法了,对于C++平台的会略有不同。

#ifndef NS_ENUM
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#endif

#ifndef NS_OPTIONS
#define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
#endif
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值