分类 block变量

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;
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页