文章目录
OC起源
OC采用的是消息结构,不是函数调用,由Smalltalk演化而来。
消息结构的语言运行时所应执行的代码由运行环境来决定。
使用函数调用的语言则由编译器来决定
函数型语言和消息结构型语言在处理多态时,查找要执行的具体方法的时机和方式不同
- 基于虚方法表的语言,如C++、Java在编译期,编译器知道类的继承关系和虚函数的签名,每一个类有一个虚方法表,表中存放该类的所有虚函数的实际内存地址,对象内部由一个隐藏指针vptr指向该类的虚表,当调用多态方法时,代码需要先通过对象的cptr指针找到虚表,在表中按照固定偏移找到函数地址,跳转执行。(运行时只查表)
- 基于消息分发类的语言,如smalltalk、Ruby、早期OC,对象之间通过发送消息来调用方法,编译器通常不绑定方法地址,甚至都不检查方法存不存在,运行时,系统查找对象所属类的方法字典,按照消息名查找对应方法的实现,会沿着继承链向上查找,找不到触发消息无法处理的机制,如调用method_missing或抛出异常,开销比较大
内存管理
OC的部分语法与C语言相同,在OC中使用指针式来指示对象。
objc
NSString* str - @"real.";
OC中所有对象都是一个objc_object结构体,我们操作的NSString* 等都是指向这些结构体的指针。这OC中的对象存储在堆/常量区。
objc
NSString* str = @"real.";
NSString* antStr = str;
我们看一下这段代码的内存分布:

分配在堆中的内存必须直接管理,分配在1栈上的用于保存变量的内存会在其栈帧弹出时自动清理
OC采用引用计数管理堆区内存
比起创建结构体,创建对象需要额外的开销,所以有时候采用结构体可以节约内存。
在类的头文件中尽量少引用其他头文件
在类的头文件中,如果我们需要引入其他文件,使用
@class就可以了,实现向前声明,还能避免循环引用

我们在引入协议时,不可以使用向前声明,因为向前声明只能告诉编译器某个协议的存在,而编译器需要知道协议中定义的方法。
多用字面量语法
OC为我们提供了许多语法糖,实现便携书写
objc
NSNumber* number = @1
NSNumber* number = @1.6f
NSNumber* number = @YES
NSNumber* number = @'a'
NSNumber* bumber = @(80);
objc
NSArray* ary = @[@"ll", @"gg", @"ff"];
ary[1]//字面量取法
objc
NSDictionary* data = [@"123":@"213"];
data[@"123"];
在使用字面量语法时,我们需要尽量避免值出现nil,避免抛出异常
多用类型变量,少用#define预处理
objc
#define ANIMATION_DURATION 0.8;
如果该宏定义在某个头文件中,那么所有引用这个头文件的代码都会被替换
objc
static const int number = 20;
限制该变量只在当前编译单元中可见,避免其他文件被污染
同时可以遵守下面几个规则:只在当前文件用的常量 → 加
k前缀在其他类中可见的话,可以使用类名来做前缀
只要不打算公开这个常量,就在.m文件中定义,并使用static const修饰(保证当前文件可见以及不可修改)
如果不采用static的话,如果在另一个实现文件中定义一个同名变量会报错
其实采用static和const一起来修饰的话,编译器其实还是和#define一样的实现,但是他会有类型信息。
在某些情况下,我们需要给外部一个可见的常量,可以像下面这样定义:
objc
extern NSString* *const tom;
extern const int duration;
//.h
NSString *const tom = @"mot";
const int duration = 30;
//.m
注意const修饰的位置,与*结合就是说修饰一个常量指针,与NSString结合就是说修饰一个常量字符串
编译器看到头文件的extern之后就会将其添加到全局符号表中,需要注意避免名称冲突
枚举
objc
enum CellType {
CellTypeSongs
};
typedef enum CellType CellType;
CellType state = CellTypeSongs;
在C++11之后我们可以指定使用何种底层数据类型
objc
typedef enum : NSUInteger { //这里保证我们的一个底层数据类型是NSInteger
<MyEnumValueA>,
<MyEnumValueB>,
<MyEnumValueC>,
} <MyEnum>;
我们也可以从某一个值开始手工枚举成员所对应的值。
objc
enum CellType {
CellTypeSongs = 1,
CellTypeAlbum
};

通过组合枚举实现多选功能
