—————————————————————————————— // 1) 创建自动释放池 //使用注意事项 Person *p = nil; p = [Person new]; [p retain]; // 2 [p release]; // @autoreleasepool{ ....... } @autoreleasepool { //注意1: 并不是把代码放到自动释放池中,对像就能自动释放了 // p = [Person new]; //注意2: 在自动释放池的外部发送autorelease消息 //注意3: 如果想要把对象加入到自动释放池中,必须在 // 自动释放池的内部调用 auturelease [p autorelease]; //注意4: 自动释放池仅仅是在释放池结束的时候,向对象发送一次release // 对象不一定会被销毁 } // [p release]; 2-->1 // [p autorelease]; //在自动释放池外部调用了autorelease,不起作用 } —————————————————————————————— +(instancetype)person{ //创建person //加入到自动释放池 //返回 //self return [[[self alloc] init] autorelease]; } // stringWithFormat // [[[NSString alloc] init:@""] autorelease]; NSString *str = [NSString stringWithFormat:@"xxxx"]; //应用: 给Person 类定义一个快速创建对象的方法 // Person *p = [Person alloc] init]; [p release]; // Person *p = [Person person]; // p 在堆区存放 // p 不会存在内存泄露 //实现步骤: // 1 定义类方法 // 2 创建对象 // 3 加入到自动释放池 // person 是一个快速创建对象的方法 //优点,可以帮我们创建对象,不需要再关心什么时候写release 或者 autorelease Person *p = [Person person]; //创建对象 [p run]; //对象创建成功,并且调用了run方法 // person 从父类继承的 //[Student person]; ---> Person //目标:[Student person]; ---> Student Student *stu = [Student person]; [stu run]; // /// Users/apple/Desktop/课堂共享/就业班/01-OC加强/0601/code/OC8-ARC和分类的使用/3-【掌握】autorelease /// 的应用场景/main.m:44:19: Incompatible pointer types initializing /// 'NSString *' with an expression of type 'Student *' // NSString Student //最好,编译的时候给个警告 NSString *str2 = [Student person]; // +(id)person; NSLog(@"str2.length = %ld", str2.length); // id 不会有警告 作为返回值 定义变量 不能判断赋值类型 // instancetype 有警告 只能作为方法的返回值 能判断赋值类型 // } —————————————————————————————— //创建一个对象 Person *p = [Person new]; // nil p = nil; NSLog(@"xxxxooooo"); } void test2() { //创建一个对象 Person *p = [Person new]; // p1是一个局部的指针变量 //局部变量的作用域: //从它定义的位置开始,到它所在的代码块的"}"结束 Person *p1 = p; // nil p = nil; NSLog(@"xxxxooooo"); } int main(int argc, const char *argv[]) { @autoreleasepool { //创建一个对象 //为什么p 没有赋值为nil也能够被释放 //因为p是一个局部变量(存放在栈区),局部变量有作用域,出了作用域,就被销毁了 //强弱指针 //强指针: 默认的指针都是强指针 //强指针,也可以使用 _ _strong 来修饰 // p 用__strong 来修饰,所以,它使一个强指针 __strong Person *p = [Person new]; p.age = 18; NSLog(@"p.age = %d", p.age); //弱指针 //弱指针:用_ _weak修饰的指针,就是弱指针 __weak Person *p1 = p; p = nil; // p被释放了,p1 被赋值为nil了 //报错? NSLog(@"xxxxxx p1.age = %d", p1.age); } return 0; —————————————————————————————— @property (nonatomic,weak) Dog *dog; @property做了三件事情 1) 生成一个实例变量 _dog,加上weak, __weak Dog *_dog; 2) 生成_dog 的get和set方法的声明 3) 实现_dog 的get和set方法 @property (nonatomic,strong) Dog *dog; 1) 生成一个实例变量 _dog,加上strong, __strong Dog *_dog; 2) 生成_dog 的get和set方法的声明 3) 实现_dog 的get和set方法 解决 循环引用 ——————————分类$———————————————————— 分类 分类:类别/类目 作用:在不修改原类的情况下,给类增加新的功能 好处: 1)团队协作 2)方法归类 使用流程: 1) 声明一个分类 格式: //含义 给类扩展一个分类,分类名称是"分类名" @interface 类名(分类名) //新增的方法的声明列表 @end //Person base // eat run //给Person扩展了一个分类,分类名称是base //扩展了 eat和run的功能 @interface Person (base) -(void)eat; -(void)run; @end 2) 实现一个分类 格式: @implementation 类名(分类名) //方法的实现 @end @implementation Person(base) -(void)eat{ NSLog(@"人在吃东西"); } -(void)run{ NSLog(@"人在跑步"); } @end 3) 使用分类 如果分类的文件是单独的,使用之前,必须要导入分类的头文件 //扩展 play 分类 // playlol playdota //扩展 study 分类 // studyC studyIOS —————————————————————————————— 分类的使用注意事项 1) 分类主要是用于在不修改原类的情况下,给类增加新的方法,不能增加实例变量 2) @property int age; 在分类中,编译不会报错,使用的时候,会报错 3) 分类中可以使用原类中的实例变量 4) 当分类中存在和原类同名的方法,优先执行分类的 // 很多分类存在同名的方法? 到底执行那个? // 执行的是最后一个编译的分类文件的同名方法 // 怎么看最后一个编译的? */ —————————————————————————————— 非正式协议: 非正式协议和 正式协议(下次课),是两码事 给NSObject 或者 NSObject子类(Foundation 框架提供的类) 增加分类 NSObject + eat NSString + count NSObject eat | | Person 注意: 非正式协议,一般原类不进行实现,而是有它的子类进行实现 —————————————————————————————— 分类 类的延展(扩展) 相同点: 可以增加新的方法 可以增加新的方法 不同点: 不可以增加实例变量 可以增加实例变量 必须得有分类的名称 一定不能有分类的名称 ——————block———————————————————————— block 是什么东西? 代码块类型 int a; 可以使用block类型,来定义该类型的变量 使用的格式: 1) 最简单的形式 返回值类型 (^block变量名)(参数列表) = ^(参数列表){ ....块的语句; }; 使用block的格式: block变量名(实参列表); void (^myblock)(); //定义block类型的变量,变量名是myblock //代码块返回值 是 void //代码块么有参数 2) 没有返回值,但是有参数的block void (^myblock2)(int a,int b) = ^(int a,int b){ NSLog(@"a + b = %d",a+b); }; */ #import <Foundation/Foundation.h> int main(int argc, const char *argv[]) { @autoreleasepool { // 1)block的最简单的形式 //没有返回值,没有参数 void (^myblock)(); //给block变量赋值 myblock = ^() { NSLog(@"我是代码块的内容"); int a = 10; NSLog(@"a = %d", a); //..... }; //使用block变量 myblock(); // 2)定义一个有参数,没有返回值的block // block变量名是 myblock2 //也可以写成:void (^myblock2)(int ,int ),只要写参数的类型和个数 void (^myblock2)(int a, int b) = ^(int a, int b) { NSLog(@"a + b = %d", a + b); }; // void (^myblock2)(int a,int b) ; // // myblock2 = ^(int a,int b){ // // NSLog(@"a + b = %d",a+b); // // }; //使用有参数的block myblock2(10, 20); // 3)有参数,有返回值的block //返回两个数的最大值 int (^myblock3)(int, int) = ^(int a, int b) { return a > b ? a : b; }; //定义变量 接收代码块执行完成后的返回值 int max = myblock3(34, 88); NSLog(@"max = %d", max); //给变量重新赋值 myblock3 = ^(int a, int b) { NSLog(@"xxxxxx"); return a + b; }; int sum = myblock3(23, 30); NSLog(@"sum = %d", sum); } return 0; } ————————typedef——block———————————————————— void test() { NSLog(@"I 'm Test!"); } //函数指针的回顾 void test2() { // test(); //定义函数指针 void (*p)(); // p就是一个指向返回值是void 类型,没有参数的函数指针 p = test; // p(); // 用函数指针,间接的调用了test函数 // 给 指向返回值是void类型,并且没有参数的函数指针,起个别名 p1 typedef void (*p1)(); p1 pp; // pp就是 和 p 一样的,都是指向返回值是void 类型,没有参数的函数指针 pp = test; pp(); } int main(int argc, const char *argv[]) { @autoreleasepool { //定义一个 没有返回值,没有参数的blockb变量 void (^myblock)(); // myblock = ^{ NSLog(@"I'm block"); }; myblock(); // 1)typedef 给无参无返回值block起别名 typedef void (^myblock2)(); // myblock2 是一个类型 myblock2 b2; // b2是一个没有返回值,没有参数的block变量 //给block变量赋值 b2 = ^{ NSLog(@"I'm bande"); }; //使用block b2(); // 2)给有参无返回值的block起个别名 //给返回值是void并且有两个整型参数的block起个别名 typedef void (^blockType1)(int, int); // blockType1 是一个类型 blockType1 bt1; bt1 = ^(int a, int b) { NSLog(@"a + b = %d", a + b); }; bt1(23, 12); // 3) 给有参有返回值的block起别名 typedef int (^blockType2)(int, int); //用blockType2类型定义一个变量bt2 并且初始化 blockType2 bt2 = ^(int x, int y) { return x > y ? x : y; }; int max = bt2(23, 45); NSLog(@"max = %d", max); } return 0; ——————————————block———————————————— void test() { //存在内存的栈区,因为是一个局部变量 int m = 10; NSLog(@"block之前:m = %d,addr = %p", m, &m); //定义一个block变量 void (^myblock)() = ^{ //思考:在block的内部能不能访问外部的m? //思考:此时block内部的 m 地址和 外部的m第地址一样吗? //注意: // 1) 此时 block 内部的m 和 外部的m是两个不同的变量 // 当我们定义block的时候,系统会自动把block外部的变量copy到堆区 // 2) 注意copy的使用是使用了const,所以,在block的内部不能修改在堆区的常量值 // 思考:为什么要以const的形式拷贝? // 原则: 我们一般不再block内部,修改外部的值,也是增强代码的可读性和易维护性 // m = 1000; NSLog(@"in block,m = %d,addr = %p", m, &m); }; m = 20; //给m重新赋值了 NSLog(@"block之后:m = %d,addr = %p", m, &m); myblock(); } int main(int argc, const char *argv[]) { @autoreleasepool { //存在内存的栈区,因为是一个局部变量 __block int m = 10; // __block 是告诉编译器 可以做一个忽略,可以在block中修改外部变量的值 // block外部的变量的指向发生改变:指向堆区的变量 NSLog(@"block之前:m = %d,addr = %p", m, &m); //定义一个block变量 void (^myblock)() = ^{ // m = 1000; // NSLog(@"m = %d",m); //1000 NSLog(@"in block,m = %d,addr = %p", m, &m); }; myblock(); m = 20; //给m重新赋值了 NSLog(@"block之后:m = %d,addr = %p", m, &m); // NSLog(@"m = %d",m); } return 0; —————————————————————————————— // block作为函数的参数使用 // wrok有一个参数,无参无返回值block类型的,workBlock是一个变量名 void work(void (^workBlock)()) { NSLog(@"起床"); NSLog(@"刷牙"); NSLog(@"去车站"); NSLog(@"坐车"); //执行block的代码段 workBlock(); // NSLog(@"了解项目"); // NSLog(@"找美女聊项目"); NSLog(@"去车站"); NSLog(@"坐车回家"); NSLog(@"吃饭"); NSLog(@"睡觉"); } void workDay(int n) { //定义新的类型 typedef void (^blockType)(); //定义block的变量 blockType w; switch (n) { case 1: w = ^{ NSLog(@"了解项目"); }; break; case 2: w = ^{ NSLog(@"分析项目"); }; break; case 3: w = ^{ NSLog(@"编写代码"); }; break; case 4: w = ^{ NSLog(@"调试项目"); }; break; case 5: w = ^{ NSLog(@"离职"); }; break; default: break; } //调用work的方法 work(w); } // void day1(){ // // NSLog(@"起床"); // NSLog(@"刷牙"); // NSLog(@"去车站"); // NSLog(@"坐车"); // // NSLog(@"了解项目"); // NSLog(@"找美女聊项目"); // // NSLog(@"去车站"); // NSLog(@"坐车回家"); // NSLog(@"吃饭"); // NSLog(@"睡觉"); // //} // // // void day2(){ // // NSLog(@"起床"); // NSLog(@"刷牙"); // NSLog(@"去车站"); // NSLog(@"坐车"); // // NSLog(@"分析项目"); // // NSLog(@"去车站"); // NSLog(@"坐车回家"); // NSLog(@"吃饭"); // NSLog(@"睡觉"); // //} // // void day3(){ // // NSLog(@"起床"); // NSLog(@"刷牙"); // NSLog(@"去车站"); // NSLog(@"坐车"); // // NSLog(@"写代码"); // // NSLog(@"去车站"); // NSLog(@"坐车回家"); // NSLog(@"吃饭"); // NSLog(@"睡觉"); // //} // // void day4(){ // // NSLog(@"起床"); // NSLog(@"刷牙"); // NSLog(@"去车站"); // NSLog(@"坐车"); // // NSLog(@"调试项目"); // // NSLog(@"去车站"); // NSLog(@"坐车回家"); // NSLog(@"吃饭"); // NSLog(@"睡觉"); // //} // // void day5(){ // // NSLog(@"起床"); // NSLog(@"刷牙"); // NSLog(@"去车站"); // NSLog(@"坐车"); // // NSLog(@"离职"); // // NSLog(@"去车站"); // NSLog(@"坐车回家"); // NSLog(@"吃饭"); // NSLog(@"睡觉"); // //} int main(int argc, const char *argv[]) { @autoreleasepool { // day1(); // day2(); // day3(); // day4(); // day5(); // // work(^{ // NSLog(@"了解项目"); // NSLog(@"找美女聊项目"); // NSLog(@"约会吧"); // }); for (int i = 1; i <= 5; i++) { workDay(i); } } return 0; } —————————————————————————————— block类型作为函数的返回值 //错误用法: void(^block)() test(){ } //解决方法: typedef void(^blockType)(); //blockType 是一个无参无返回值的block类型 */ #import <Foundation/Foundation.h> // blockType 是一个无参无返回值的block类型 typedef void (^blockType)(); int sum(int x, int y) { //返回的是一个整型值 return x + y; } // void(^block)() test(){ // // // //} // test函数需要返回一个 无参 无返回值的一个代码块 blockType test() { //定义一个blockType类型的变量 bt blockType bt = ^{ NSLog(@"I'm bt block"); }; //把bt变量值返回 return bt; } typedef int (^blockType2)(int, int); //定义返回值是 一个 有参数有返回值的类型的block 的函数 blockType2 test2() { return ^(int a, int b) { return a + b; }; } int main(int argc, const char *argv[]) { @autoreleasepool { // int s = sum(34, 12); // NSLog(@"s = %d",s); //定义blockType类型的block变量 b2 blockType b2 = test(); // b2存得就是test返回的那个代码块 //使用block b2(); blockType2 bb = test2(); /** * bb = ^(int a,int b){ return a+b; }; */ int ss = bb(10, 20); NSLog(@"ss = %d", ss); } return 0; } —————————————————————————————— #import "Person.h" //定义新的类型 typedef void (^blockType)(); // block作为函数的参数使用 // wrok有一个参数,无参无返回值block类型的,workBlock是一个变量名 // work(2) void work(int n) { NSLog(@"起床"); NSLog(@"刷牙"); NSLog(@"去车站"); NSLog(@"坐车"); //执行block的代码段 // workBlock(); // NSLog(@"了解项目"); // NSLog(@"找美女聊项目"); blockType workDay(int n); //调用workDay 并且定义blockType类型的 变量bt接收函数的返回值 blockType bt = workDay(n); bt(); NSLog(@"去车站"); NSLog(@"坐车回家"); NSLog(@"吃饭"); NSLog(@"睡觉"); } blockType workDay(int n) { //定义block的变量 blockType w; switch (n) { case 1: w = ^{ NSLog(@"了解项目"); }; break; case 2: w = ^{ NSLog(@"分析项目"); }; break; case 3: w = ^{ NSLog(@"编写代码"); }; break; case 4: w = ^{ NSLog(@"调试项目"); }; break; case 5: w = ^{ NSLog(@"离职"); }; break; default: break; } //调用work的方法 // work(w); return w; } int main(int argc, const char *argv[]) { @autoreleasepool { // for(int i=1;i<=5;i++){ // // work(i); // // } Person *p = [Person new]; [p test:^{ NSLog(@"xxxxxx"); }]; blockType b1 = [p test2]; b1(); [p test3:^{ NSLog(@"test3"); }]; } return 0; } ——————————————————— ——————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— —————————————————————————————— ——————————————————————————————