IOS学习第25天
分类
- 分类的使用注意
1.在分类中不能写属性,只能写方法的声明和实现
2.可以用@property,但是即使使用了@property,也不会生成属性,只会生成setter和getter方法的声明
3.在分类中可以访问本类中的真私有属性,但是只能通过setter和getter方法访问
4.分类中的方法可以和本类的方法同名,当调用的时候,不管有没有引入分类,都会调用分类的方法,如果分类中有同名的方法,只会调用最后编译的那个分类中的方法
- 分类的使用场景
1.团队开发:多人共同写一个类的时候
2.当一个类方法非常多,功能很复杂的时候,代码和方法写到一个类中,不易于后期的维护和修改
非正式协议
就是一个分类,市委系统类添加方法的分类
延展的基本使用
1.延展是什么?(Extension)
一个特殊的分类:
1>是一个匿名的分类(就是一个分类没有名字)
2>在延展中可以有属性,但是只有方法的声明,而没有方法的实现(方法的实现在本类的.m文件中)
2.如何写一个延展
@interface 本类名 ()//小括号中什么都不写,这就是延展
@end
"注意:延展没有实现,和本类共用一个实现
3.延展的使用注意:
1>普通的分类(有名字):
不能写属性,可以写方法的声明 和实现
普通分类中可以使用@property,只会生成方法的声明
2>延展(没有名字)
可以属性,可以有方法的声明,延展的实现在本类中
延展中可以使用@property,会有属性,也会有方法的声明和实现
1.延展的作用:"生成私有的@property和私有方法
@property 会生成属性,方法声明,方法实现
1>什么是私有的@property?就是生成的属性,方法声明和实现都不让外界访问
2>怎么办?
在.m中 可以写一个延展,然后把@property 写到延展里
这样生成的_属性名,getter和setter方法的声明都在.m文件中
2.延展如何使用?
1>大部分的情况下 延展都会写在本类的.m文件中,而且是写到最上面
2>然后可以在延展中写属性和方法,这些属性和方法都是私有的成员
"总之:
延展就是用来私有化成员的,只要你想写一个私有的成员(属性,方法)
写就到延展中
"掌握":1.延展怎么写(写到本类的.m中) 2.延展里面写什么 (你要私有化成员)
block变量
- block变量的声明
1.block是一个数据类型,它的变量可以存一段符合要求的代码
2.block变量的声明
返回值类型 (^变量名)(参数列表)
void (^block1)()
int (^block2)(int num1,int num2)
- block变量赋值/初始化
1.写一个block代码块的格式
^返回值类型(参数列表){
//代码
};
2.写一个代码块 求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;
};
4.执行block变量中的代码
格式:
block变量名字(实参列表);
需要参数就传进去
如果有返回值 就接收
- block的简写
] 注意:"声明block变量时的小括号不能省略
代码段:"打印两句"凤姐我爱你"
^void{
NSLog(@"凤姐我爱你");
NSLog(@"凤姐我爱你");
};
2.在写代码段时可以省略返回值类型,系统会自动判断返回值的类型
1>如果这个代码段没有返回值,系统 默认会是void
2>如果这个代码段有返回值 系统会根据返回值类型 来判断代码段返回值类型
二."block变量的简写
1..在声明block变量时,参数可以只写类型 而不写名称
注意:"代码段中类型和名称都不可以省略
int (^blockSum)(int,int);//这里小括号中的参数名字可以省略,但是类型不能省略
^int(int num1,int num2){
int num3 = num1 + num2;//如果这时候省略了参数的名称 那么就发求和
return num3;
};
"注意:我们写代码不简写,但是你必须能看懂别人的简写方式
- 使用typedef简化block定义
1.typedef 的作用是?
为一个已经存在的数据类型,起一个数据类型
2.使用typedef简化block的定义
1>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];
2>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访问外部变量
1.block代码段内部,可以定义和外部变量名字相同的变量
2.在block代码段的内部,
1>可以访问外部的全局变量和局部变量的值
2>可以修改外部全局变量的值 ,但是不能修改外部局部变量
如果非要修改外部的局部变量的值,那么必须给外部这个局部变量前加上__block修饰
- block作为函数的参数
1.block作为函数的参数的写法
//第一种方式难看 恶心
void test(返回值类型 (^block变量名)(参数列表))
{
}
//第二种
typedef void (^NewType)(int num1,int num2);//给block类型 起了一个别名 NewType
void test(NewType block1)
{
}
2.在函数内部如果执行block代码
typedef void (^NewType)(int num1,int num2);//给block类型 起了一个别名 NewType
void test(NewType block1)
{
//在函数内部 如果执行block1中的代码
block1(有参数写参数,没参数拉倒);//
//有返回值就接收
}
3.调用这个函数的方法
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>写一个函数模拟 下载音频 解析数据 并且调用音乐播放器播放
#import <Foundation/Foundation.h>
void downloadAV()
{
//1.下载数据
NSLog(@"正在下载数据..");
//2.解析数据
NSLog(@"正在解析数据..");
//3.调用调用视频播放器播放
NSLog(@"正在用Qviod播放视频");
}
void downloadMP3()
{
//1.下载数据
NSLog(@"正在下载数据..");
//2.解析数据
NSLog(@"正在解析数据..");
//3.调用音乐播放器播放MP3
NSLog(@"正在用QQ音乐 播放MP3");
}
void downloadHM()
{
//1.下载数据
NSLog(@"正在下载数据..");
//2.解析数据
NSLog(@"正在解析数据..");
//3.调用音乐播放器播放MP3
NSLog(@"正在用黑马专用播放器 播放.HM");
}
void downloadEverything(void (^handlerBlock)())
{
//1.下载数据
NSLog(@"正在下载数据..");
//2.解析数据
NSLog(@"正在解析数据..");
//3.怎么看这个文件,需要调用者告诉我
//需要调用者给我一段代码,我执行这段代码
//所以需要调用者传递给我一段代码
//所以函数需要一个block类型的参数
handlerBlock();//执行调用则传递进来的代码
}
int main(int argc, const char * argv[]) {
//函数内部 不知道怎么播放某个文件,需要调用者告诉他
//调用函数 下载东西,解析东西
// downloadEverything(^{
// //下载视频
// NSLog(@"调用Qviod播放");
// });
// downloadEverything(^{
// //下载音乐
// NSLog(@"用YY播放");
// });
return 0;
}