OC加强day03
分类的简单使用
- 什么是分类
- 当一个类包含了非诚多的术语不同范畴的方法的时候 我们通常将这个类分为多个文件来实现,其中一个类叫主类/本类其余的叫分类
- 有了分类之后 一个类 = 所有分类 + 本类
- 如何添加分类
- newFile–> 选中OC File–>选择category—>填写分类名,本类名
- 分类的声明
@interface 本类名 (分类名)
@end
@implementation 本类名 (分类名)
@end
* 分类的使用注意*
- 在分类中不能写属性,只能写方法的声明和实现
- 在分类中用@property也是可以的
- 但是即使使用了 @property 也不会生成属性,只会生成getter和getter方法的声明(不包含实现)
- 在分类中可不可以访问本类的中的属性? 可以
- 在分类中 不能直接访问本类中的真私有属性,但是通过getter各setter方法来访问本类的真私有属性
- 本类中的方法和本类的方法能不能同名? 可以
- 这个时候 不管有没有引入分类 都会调用分类的方法
- 如果多个分类中有同名的方法 只会调用最后边编译的那个分类中的方法
- 怎么看那个分类是最后编译的?
选中项目—>选中Target—>Build Phase–>编译源(Compile Source)–>在此修改顺序即可
- 总结: 分类的使用场景
- 团队开发对个人共同写一个类的时候
- 当一个类方法非常多的 功能复杂的时候
非正式协议
- 其实非正式协议就是一个分类,是为系统类添加的分类
延展的基本使用
- 延展是什么?
- 一个特殊的分类:
- 是一个匿名的分类(就是一个分类没有名字)
- 在延展中可以有属性,但是只有方法的声明,而没有方法的实现(方法的实现在本类的.m文件中)
- 如何写一个延展
@interface 本类名 () // 小括号中什么都不写 就是延展
@end
- 注意:延展没有实现,和本类共同用一个实现
- 延展的使用注意
- 普通的分类(有名字):
- 不能写属性,可以写方法的声明和实现。
- 普通分类中可以使用@property,只会生成方法的声明
- 延展(没有名字)
- 可以写属性,可以有方法的声明,延展的实现在本类中
- 延展中可以使用@property,会有属性也会有方法的声明和实现
- 普通的分类(有名字):
延展的基本使用
- 延展的作用: 生成私有的@property和私有方法
- @property 会生成属性,方法的声明,方法实现
- 什么是私有的@property? 就是生成的属性,方法的声明和实现都不让外界访问
- 怎么办?
- 在.m中 可以写一个延展,然后把@property 写到延展里 这样生成的_属性名,getter和setter方法的声明都在.m文件中
- 延展如何使用?
- 大部分的情况下,延展都会写在本类的.m文件中,而且是写到最上面
- 然后可以在延展中写属性的方法,这些属性和方法都是私有的成员
- 总之:
- 延展就是用来私有化成员的,只要你想写一个私有的成员(属性,方法)
- 写到延展中
block变量的声明
- block是一个数据类型,它的变量可以存 一段符合要求的代码
- block变量的声明:
返回值类型 (^变量名)(参数列表);
xxx (^ttt)(xxx a,ooo b);
声明了一个block类型的变量, 变量名字叫做ttt;
ttt可以储存 返回值类型是 xxx 有一个xxx类型的参数 一个ooo类型的参数
block变量赋值初始化
- 写一个block代码块的格式
^返回值类型(参数列表){
代码;
}
- 写一个代码块 求2个整数的和
^int(int num1,int num2){
//代码功能就是求和
// return num1+num2;
int num3 = num1 + num2;
return num3;
};
写一个代码块 求2个整数的最大值
^int(int num1,int num2){
//代码块 求num1,和num2中的最大值
int max = num1 > num2 ? num1 : num2;
return max;
};
3.保存上面的2个代码块
3.1>//第一种
int (^blockSum)(int num1,int num2);//定义了一个变量
blockSum = ^int(int num1,int num2){
//代码功能就是求和
// return num1+num2;
int num3 = num1 + num2;
return num3;
};
//第二种
int (^blockSum)(int num1,int num2) = ^int(int num1,int num2){
//代码功能就是求和
// return num1+num2;
int num3 = num1 + num2;
return num3;
};
3.2>//第一种
int (^blockMax)(int num1,int num2);//定义了一个变量
blockMax = ^int(int num1,int num2){
//代码块 求num1,和num2中的最大值
int max = num1 > num2 ? num1 : num2;
return max;
};
//第二种
int (^blockMax)(int num1,int num2) = ^int(int num1,int num2){
//代码块 求num1,和num2中的最大值
int max = num1 > num2 ? num1 : num2;
return max;
};
- 执行block变量中的代码
- 格式:
- block变量名字(实参列表)
- 需要参数就穿进去
- 如果有返回值 就接收
- 格式:
block 使用 typedef的简化 定义
- typedef 的作用是?
- 为一个已经存在的数据类型,起一个 别名
- 使用typedef简化block的定义
- typedef的基本使用
typedef long int Lint;
int nums1[4];//int[4] nums1;
int nums2[4];//int[4] nums2;
typedef int NUM[4];
NUM nums3;//等价于 int nums3[4];
- typedef简化block的定义
“`
void (^blockName)(int,int);
//void (^)(int,int) blockName;==>XXX a;
语法格式:
// typedef void (^)(int,int) NewType;
typedef 返回值类型 (^新类型名字)(参数列表);
typedef void (^NewType)(int,int);
这个NewType就是新类型的名字
就可以通过NewType 来定义block变量
NewType block1,block2;
**block访问外部变量的问题**
- block代码段内部,可以定义和玩不变量名字相同的变量
- 在block代码段的内部
- 可以访问外部的全局变量和局部变量的值
- 可以修改全局变量和自己的局部变量的值 但是不能修改外部局部变量的值
- 如果非要修改 就子啊外部的局部变量的值 定义的时候前面加上 __block修饰
**block作为函数的参数**
- block作为函数的参数的写法
void test(返回值类型 (^变量名)(参数列表1,参数列表2))
{
}
//第二种
typedef void (^NewType)(int num1,int num2);
void test(NewType block1)
{
}
- 在函数内部如何执行block代码
typedef void(^NewType)(int num1, int num2)
void tese(NewType block1)
{
block1(有参数写参数 没参数拉倒)
//有返回值就接收
}
- 调用这个函数的终极方法
1>定义一个block变量 给他赋值
NewType block2 = ^void(int num1,int num2){
int num3 = num1 + num2;
NSLog(@"num3 = %d",num3);
};
2>调用函数
test(block2);
3>终极版
test(^void(int num1,int num2){
int num3 = num1 + num2;
NSLog(@"num3 = %d",num3);
});//有一个小技巧,调用函数的时候 如果需要传递代码块,只需要敲回车键,自动添加代码块的格式
- "注意:定义block变量的时候,block内的代码不会执行
"block内的代码只有在调用block的时候才执行
4.例子:
1>写一个函数模拟 下载数据 解析数据 并且调用视频播放器播放
2>写一个函数模拟 下载音频 解析数据 并且调用音乐播放器播放