本系列为《Effective Objective-C 2.0》的阅读笔记,通过对此书内容的理解记录下用Objective-C语言写程序时重要的知识点.本文为该书的第一章知识内容的理解和总结.
Objective-C语言与一般面向对象语言的区别
Objective-C使用消息结构的语言, 而不是像C,C++,Java等使用函数调用的面向对象语言.而消息结构语言的特点为运行期间的所执行的代码都有运行环境决定;并非编译器决定.消息结构语言的动态绑定特性:方法调用时会在运行时通过"虚方法表"所查找对应的方法,编译器不关心接收消息的对象的本身类型, 也是在运行时确定.
Objective-C语言的动态绑定体现
[person run];
// 底层Runtime组件将执行代码转如下
objc_msgSend(id person, @selector(run))
// 通过run对应生成的SEL指针在(person所属对象的类)虚方法表中寻找对应的IMP执行方法,
// 若没有找到则抛出"unrecognized selector sent to instance "异常并Crash.
Objective-C的对象与指针关系
Objective-C语言中的指针用来指示对象,对象本身的内存分配在堆,指针变量的内存分配在栈,并且指针变量内存存储的对象的内存地址.
NSString *name = @"wrcj";
NSString *anotherName = name;
头文件引用的注意点
针对不需要知道所引入的头文件的具体细节,使用@class
头引入文件能减少编译时间,提高编译效率.
针对将用到所要引入的头文件的具体接口内容的情况,优先考虑在类扩展(extension)处引入该头文件中.
Warn: 在各自头文件中使用'#include'引入对方的头文件,会导致文件间的"循环引用",编译器无法正确编译.
充分利用字面量语法
在程序执行上,使用字面量语法更加安全,有效.
NSString *nameA = @"nameA";
NSString *nameB = nil;
NSString *nameC = @"nameC";
NSArray *normalArray = [NSArray arrayWithObjects: nameA, nameB, nameC, nil]; // 只有nameA一个元素,nameC没有被加入数组,遇到nil直接结束元素的添加.
NSArray *literalArray = @[nameA, nameB, nameC]; // 代码执行到此处"attempt to insert nil object from objects[1]" Crash
使用类型常量,尽量少用#define
对于特定实现文件内的全局常量,使用static
关键字限定常量的可见范围和const
定义为常量类型.若常量局限于执行文件内容可见,则命名k字母开始,若在类之外可见,只添加类前缀防止重复.
static NSString* const kCellIdentity = @"PhotoCell"
宏定义常量缺点:1.不带类型信息的简单文本替换 2.容易能被修改
类似通知名的全局常量定义实现
// header file
extern NSString *const WRStringConstant;
// implement file
NSString *const WRStringConstant = @"Value"
编译器遇到extern
关键字,会在全局符号表创建一个叫WRStringConstant
的符号,表示特定常量,存在于编译生成的二进制数据文件,允许其他代码使用.
Objective-C中枚举使用
枚举通常用来表示状态,选项和状态码,配合逻辑运算符还进行选项等枚举的组合和操作.
以下为系统推荐的两种枚举类型定义的方式
typedef NS_ENUM(NSUInteger, WRGameState) {
WRGameStateIdel = 1 << 0,
WRGameStateWalk = 1 << 1,
WRGameStateRun = 1 << 2,
WRGameStateAttack = 1 << 3,
WRGameStateDead = 1 << 4
};
typedef NS_OPTIONS(NSUInteger, WRPersonState) {
WRPersonStateIdel = 1 << 0,
WRPersonStateWalk = 1 << 1,
WRPersonStateRun = 1 << 2,
WRPersonStateDead = 1 << 3
};
对当前枚举状态,使用与操作符(&)检查状态是否有特定的枚举状态
WRPersonState currentPersonState = WRPersonStateRun | WRPersonStateWalk;
if (currentPersonState & WRPersonStateWalk) { //对当前状态进行走路状态的与操作,查看是否存在走路状态
NSLog(@"walking");
}
// "walking"
枚举状态的其他操作: 进行或操作(|)表示打开该特定状态,进行与异操作(&~)表示关闭该特定状态.
NS_ENUM: 针对编辑器对新枚举支持性判断选用合适的枚举定义方式,适用大部分枚举类型定义.
NSOPTIONS 用于表示需要组合运算的枚举.(原因:在C++模式编译下,不允许底层数据类型运算后向枚举类型的"隐式转换")
Tips: 对枚举的Switch用法,不要添加default语句,方便后期枚举值添加后编译器发警告缺少对新状态的处理.