undefined

1. 延展:Extension

是一个特殊的 category(分类),所以延展也是类的一部分。特殊之处:

  1. 延展这个特殊分类没有名字
  2. 只有声明,没有实现。和本类共享一个实现
  3. 只有一个 .h 文件,文件名称:本类名_取得文件名.h 这个文件只有延展的声明。实现可以放在本类中

语法:

1
2
@interface 类名 () {
}

延展和分类(category)的区别

  • 分类有名字,延展没有名字。是一个匿名的分类
  • 每一个分类都有单独的声明和实现,而延展只有声明,没有单独的实现,和本类共享一个实现
  • 分类中只能新增方法,而延展中任意的成员都可以写
  • 分类中可以写 @property,但是只会生成 getter、setter 的声明。延展中写 @property 会自动生成私有属性,也会生成 getter、setter 的声明与实现

适用场景

  • 要为类写一个私有的 @property (生成的 getter、setter 方法只能在类的内部访问,不能在外部访问)
  • 延展一般情况下不会独占一个文件,都是将延展写在本类的实现文件中。这个时候,写在延展中的成员,就相当于这个类的私有成员,只能在本类的实现中访问,外部不能访问
  • 延展天生就是来私有化类的成员的。如果类的成员只希望在类的内部访问,那么就将其定义在延展中。

2. block 数据类型

block 是一个数据类型,可以声明一个 block 类型的变量。block 类型的变量中专门存储一段代码。这段代码可以有参数,可以有返回值。

在声明 block 变量时,必须要指定 block 存储的代码段是否有参数、是否有返回值。一旦指定以后,这个 block 变量中就只能存储这样的代码了。

格式:

1
2
3
4
5
6
7
8
返回值类型 (^block变量的名称)(参数列表);
int (^myBlock)(int num); // 表示声明了一个 block 类型的变量叫做 myBlock,这个变量只能存储返回值为 int,有一个 int 型参数的代码段

myBlock = ^int(int num) {
return num;
};

int res = myBlock(10); // 执行

注意:赋值给 block 变量的代码段,必须要符合 block 变量的要求,否则就会报错。

关于 block 的简写:

  • 如果我们写的代码段没有返回值,那么代码段的 void 可以省略。声明 block的变量的返回值不可以省略

    1
    2
    3
    void (^myBlock)() = ^{
    ....
    };
  • 如果代码段没有参数,那么代码段的小括号可以省略。

  • 当一个代码段既没有参数、也没有返回值的时候。 void (^myBlock)() = ^{};

  • 声明block 变量的时候,如果有指定参数,可以只写参数的类型而不写参数的名称。

    1
    int (^myBlock)(int, int);
  • 无论代码段是否有返回值,在写代码的时候,可以不写返回值的类型。编译器会自动的确定返回值的类型。

使用 typedef 简化 block 变量的复杂定义

1
2
3
typedef void (^NewType)();
NewType block1;
NewType block2;

block 对于外部变量的访问

  • 在 block 代码块的内部可以取定义在外部的变量的值,定义在外部的局部变量和全局变量
  • 在 block 代码块的内部可以修改全局变量的值,但是不能修改定义在外部的局部变量的值
  • 如果希望我们定义的局部变量可以允许在 block 代码的内部去修改,那么可以为这个局部变量加一个 __block 的修饰符

block 做为函数参数、函数返回值(最好使用 typedef 定义)

3. 协议 protocol

专门用来声明一大堆方法(不能声明属性,也不能实现方法,只能用来写方法的声明)。只要某个类遵守这个协议,就相当于拥有这个协议中的所有的方法声明

协议的声明,只有一个 .h 文件

1
2
3
@protocol 协议名称 <NSObject>
方法的声明
@end

类遵守协议

  • 如果想要让一个类,拥有协议中定义的所有的方法声明,那么就让这个类遵守这个协议
  • 类只要遵守一个协议,那么这个类就拥有了这些协议中定义的所有的方法的声明了
1
2
@interface 类名 : 父类名 <协议名称1, 协议名称2>
@end
  • 如果类不实现协议中的方法,编译不会报错,但是运行时调用方法会报错。

  • 类是单继承,但是协议可以多遵守

@required 和 @optional

  • 专门用来修饰协议中的方法。默认是 @required 修饰符
  • 在协议中,如果方法的声明被 @required 修饰,那么遵守这个协议的类必须要实现这个方法,否则编译器会发出警告;如果被 @optional 修饰,那么遵守这个协议的类如果不实现这个方法,编译器也不会警告

协议可以从另外一个协议继承,并且可以多继承

1
2
@protocol 协议名称 <父协议名称>
@end
  • 子协议中不仅有自己的方法的声明,还有父协议中的所有的方法的声明。如果一个类遵守了某份协议,那么这个类就拥有这个协议和父协议中的所有的方法声明
  • NSObject 既是 OC 的基类,又是协议。要求所有的协议都必须直接或间接的从 NSObject 基协议继承

协议的类型限制

  • 这个时候,这个指针可以指向遵守了指定协议的任意对象,否则就会报警告。当然也可以完全使用 id 指针。可以指定多个协议。

    1
    2
    NSObject<协议名称1, 协议名称2> *指针名;
    id<协议名称1, 协议名称2> 指针名;