1. 延展:Extension
是一个特殊的 category(分类),所以延展也是类的一部分。特殊之处:
- 延展这个特殊分类没有名字
- 只有声明,没有实现。和本类共享一个实现
- 只有一个 .h 文件,文件名称:
本类名_取得文件名.h
这个文件只有延展的声明。实现可以放在本类中
语法:
1 | @interface 类名 () { |
延展和分类(category)的区别
- 分类有名字,延展没有名字。是一个匿名的分类
- 每一个分类都有单独的声明和实现,而延展只有声明,没有单独的实现,和本类共享一个实现
- 分类中只能新增方法,而延展中任意的成员都可以写
- 分类中可以写 @property,但是只会生成 getter、setter 的声明。延展中写 @property 会自动生成私有属性,也会生成 getter、setter 的声明与实现
适用场景
- 要为类写一个私有的 @property (生成的 getter、setter 方法只能在类的内部访问,不能在外部访问)
- 延展一般情况下不会独占一个文件,都是将延展写在本类的实现文件中。这个时候,写在延展中的成员,就相当于这个类的私有成员,只能在本类的实现中访问,外部不能访问
- 延展天生就是来私有化类的成员的。如果类的成员只希望在类的内部访问,那么就将其定义在延展中。
2. block 数据类型
block 是一个数据类型,可以声明一个 block 类型的变量。block 类型的变量中专门存储一段代码。这段代码可以有参数,可以有返回值。
在声明 block 变量时,必须要指定 block 存储的代码段是否有参数、是否有返回值。一旦指定以后,这个 block 变量中就只能存储这样的代码了。
格式:
1 | 返回值类型 (^block变量的名称)(参数列表); |
注意:赋值给 block 变量的代码段,必须要符合 block 变量的要求,否则就会报错。
关于 block 的简写:
如果我们写的代码段没有返回值,那么代码段的 void 可以省略。声明 block的变量的返回值不可以省略
1
2
3void (^myBlock)() = ^{
....
};如果代码段没有参数,那么代码段的小括号可以省略。
当一个代码段既没有参数、也没有返回值的时候。
void (^myBlock)() = ^{};
声明block 变量的时候,如果有指定参数,可以只写参数的类型而不写参数的名称。
1
int (^myBlock)(int, int);
无论代码段是否有返回值,在写代码的时候,可以不写返回值的类型。编译器会自动的确定返回值的类型。
使用 typedef 简化 block 变量的复杂定义
1 | typedef void (^NewType)(); |
block 对于外部变量的访问
- 在 block 代码块的内部可以取定义在外部的变量的值,定义在外部的局部变量和全局变量
- 在 block 代码块的内部可以修改全局变量的值,但是不能修改定义在外部的局部变量的值
- 如果希望我们定义的局部变量可以允许在 block 代码的内部去修改,那么可以为这个局部变量加一个
__block
的修饰符
block 做为函数参数、函数返回值(最好使用 typedef 定义)
3. 协议 protocol
专门用来声明一大堆方法(不能声明属性,也不能实现方法,只能用来写方法的声明)。只要某个类遵守这个协议,就相当于拥有这个协议中的所有的方法声明
协议的声明,只有一个 .h 文件
1 | @protocol 协议名称 <NSObject> |
类遵守协议
- 如果想要让一个类,拥有协议中定义的所有的方法声明,那么就让这个类遵守这个协议
- 类只要遵守一个协议,那么这个类就拥有了这些协议中定义的所有的方法的声明了
1 | @interface 类名 : 父类名 <协议名称1, 协议名称2> |
如果类不实现协议中的方法,编译不会报错,但是运行时调用方法会报错。
类是单继承,但是协议可以多遵守
@required 和 @optional
- 专门用来修饰协议中的方法。默认是 @required 修饰符
- 在协议中,如果方法的声明被 @required 修饰,那么遵守这个协议的类必须要实现这个方法,否则编译器会发出警告;如果被 @optional 修饰,那么遵守这个协议的类如果不实现这个方法,编译器也不会警告
协议可以从另外一个协议继承,并且可以多继承
1 | @protocol 协议名称 <父协议名称> |
- 子协议中不仅有自己的方法的声明,还有父协议中的所有的方法的声明。如果一个类遵守了某份协议,那么这个类就拥有这个协议和父协议中的所有的方法声明
- NSObject 既是 OC 的基类,又是协议。要求所有的协议都必须直接或间接的从 NSObject 基协议继承
协议的类型限制
这个时候,这个指针可以指向遵守了指定协议的任意对象,否则就会报警告。当然也可以完全使用 id 指针。可以指定多个协议。
1
2NSObject<协议名称1, 协议名称2> *指针名;
id<协议名称1, 协议名称2> 指针名;