什么是自动释放池?
autorelease是一种支持引用计数的内存管理方式,只要给对象发送一条autorelease消息,会将对象放到一个自动释放池中,当自动释放池被销毁时,会对池子里面的所有对象做一次release操作
自动释放池的优点是什么?
1.不用再担心对象释放的时间
2.不用再关心什么时候添加release
自动释放池的原理?
autorelease实际上只是把对release的调用延迟了,对于每一个autorelease,系统只是把该对象放入了当前的autorelease pool中,当该pool被释放时,该pool中的所有对象会被调用release。
如何使用自动释放池?
第一种:
NSAutoreleasePool *autoreleasePool = [[NSAutoreleasePool alloc] init]; Person *p = [[[Person alloc] init] autorelease]; [autoreleasePool release];
第二种:
@autoreleasepool { // 创建一个自动释放池 Person *p = [[[Person alloc]init] autorelease]; } // 销毁自动释放池(会给池子中所有对象发送一条release消息)
自动释放池的注意:
自动释放池的存储
如果存在多个自动释放池时候,自动释放池是以 "栈" 的形式存储在堆中,而 "栈" 的特点就是 "先进后出"
什么是ARC
Automatic(自动) Reference(引用) Counting(计数器)
ARC的原理
当ARC开启时,编译器将自动在代码合适的地方插入retain, release和autorelease,而作为程序猿,完全不需要担心编译器会做错(除非开发者自己错用ARC了)。
ARC的优点
ARC的原则是什么?什么是强指针?什么是弱指针?
只要还有一个强指针指向对象,那么这个对象就会一直保持在内存中,不会被释放(除非程序退出)
强指针: 被 _strong 修饰的指针变量就是强指针
默认所有的指针变量都是强指针
Person *p1 = [[Person alloc] init]; __strong Person *p2 = [[Person alloc] init];
弱指针: 被 _weak 修饰的指针变量就是弱指针
__strong Person *p = [[Person alloc] init];
ARC中怎么对对象进行内存管理
首先我们需要了解ARC下@property修饰符有哪些?
对单个对象管理
1.ARC下,所有的指针都是强指针
2.ARC下,A对象想用有B对象,那么就需要用一个强指针指向B对象
3.当A对象不想用B对象了,什么都不需要做,系统会自动帮我们做
ARC下多对象内存管理(strong ,weak, assign)
// 在ARC中保存一个对象用strong, 相当于MRC中的retain @property(nonatomic, strong)Dog *dog; // 在ARC中如果保存对象不要用assign, 用weak // assign是专门用于保存基本数据类型的, 如果保存对象用weak @property(nonatomic, weak)Person *owner;
ARC下怎么解决循环引用问题?
ARC和MRC一样, 如果A拥有B, B也拥有A, 那么必须一方使用弱指针 也就是说 一端用strong ,一端用weak
ARC下如何兼容非ARC
找到project->targets->Bulid Phases->Compiles Sources->找到相关文件右击右边Compiler Flags添加相关代码
转非ARC: -fno-objc-arc
转ARC: -f-objc-arc (不常用,想在的Xcode默认就是ARC)
如何通过Xcode将MRC转为ARC
Edit->Convert->To Objective ARC
Category是什么
Category是OC特有的语法,Category有很多种翻译: 分类 / 类别 / 类目 (一般叫分类)
作用:
1.在不改变原来类的基础上为这个类拓展一些方法
2.一个庞大的类可以分模块开发,多人开发,更有利于团队开发
分类的格式
// 分类的声明 @interface ClassName (CategoryName) NewMethod; //在类别中添加方法 //不允许在类别中添加变量 @end ClassName: 需要给哪个类扩充方法 CategoryName: 分类的名称 NewMethod: 扩充的方法 // 分类的实现 @implementation ClassName(CategoryName) NewMethod ... ... @end ClassName: 需要给哪个类扩充方法 CategoryName: 分类的名称 NewMethod: 扩充的方法
Xcode创建分类
分类的注意
1.分类用于给原有类添加方法,只能添加方法,不能添加成员变量
2.分类中的@property, 只会生成setter/getter方法的声明, 不会生成成setter/getter方法的实现以及私有的成员变量
3.可以在分类中访问原有类 .h 中的成员
4.如果分类中有和原有类同名的方法,会调用分类中的,也就是说会忽略原有类的方法
分类,原来类或者父类中的方法调用的顺序?
分类(最后参与编译的优先) --> 原有类 -->父类
什么是类扩展
延展类别又称为扩展(Extension),Extension是Category的一个特例
类扩展的书写格式
@interface 类名 () @end
类扩展的作用
写在.m文件中,可以为某个类扩充一些私有的成员变量和方法
什么是block
Block是iOS中一种比较特殊的数据类型,用来保存某一段代码
block的作用
Block用来保存某一段代码, 可以在恰当的时间再取出来调用 功能类似于函数和方法
Block的格式:
返回值类型 (^block变量名)(形参列表) = ^(形参列表) { };
1.无参无返回值
// void代表block将来保存的代码没有返回值 // ()代表block将来保存的代码没有形参 // (^roseBlock) 代表reseBlock是一个block变量, 可以用于保存一段block代码 void (^roseBlock) (); // 如果block没有参数, 那么^后面的()可以省略 roseBlock = ^(){ printf(" {@} /n"); printf(" | /n"); printf(" //|/ /n"); printf(" | /n"); }; // 要想执行block保存的代码, 必须调用block才会执行 roseBlock(); roseBlock();
2.有参无返回值
void (^roseBlock) (int); roseBlock = ^(int num){ for (int i = 0; i < num; ++i) { printf(" {@} /n"); printf(" | /n"); printf(" //|/ /n"); printf(" | /n"); } }; roseBlock(2);
3.有参有返回值
int (^sumBlock) (int, int); sumBlock =^(int value1, int value2){ return value1 + value2; }; NSLog(@"sum = %i", sumBlock(10, 40));
首先回顾下给指向函数起别名
typedef int (*calculte)(int, int); int (*sumP)(int, int); // sumP = sum; calculte sumP = sum; NSLog(@"sum = %i", sumP(20, 10)); // int (*minusP)(int, int); // minusP = minus; calculte minusP = minus; NSLog(@"minus = %i", minusP(20, 10));
给block起别名
// 注意: 利用typedef给block起别名, 和指向函数的指针一样, block变量的名称就是别名 typedef int (^calculteBlock)(int , int); calculteBlock sumBlock = ^(int value1, int value2){ return value1 + value2; }; NSLog(@"sum = %i", sumBlock(20, 10)); // int (^minusBlock)(int , int); calculteBlock minusBlock = ^(int value1, int value2){ return value1 - value2; }; NSLog(@"minus = %i", minusBlock(20, 10));
block的应用场景
当发现一段代码前后一样,中间不一样时,这个时候可以用block
1,怎么访问和修改外部变量
int a = 10; void (^myBlock)() = ^{ NSLog(@"a = %i", a); }; myBlock();
修改
__block int a = 10; void (^myBlock)() = ^{ a = 20 NSLog(@"a = %i", a); }; myBlock();
2.为什么不可以在block中修改外部变量的值
int a = 10; NSLog(@"&a = %p", &a); void (^myBlock)() = ^{ // a = 50; NSLog(@"&a = %p", &a); NSLog(@"a = %i", a); }; a = 20; myBlock();
3.__block的应用场景
如果想在block中修改外部变量的值,那么必须在外部变量前面加上 __block
__block int a = 10; NSLog(@"&a = %p", &a); void (^myBlock)() = ^{ a = 50; NSLog(@"&a = %p", &a); NSLog(@"a = %i", a); }; myBlock(); NSLog(@"a = %i", a);
4.为什么要加上 __block 才能再block中修改外部变量的值
因为加上 __block 后就是地址传递
5.block的存储位置
6.怎么对block进行内存管理
__block Person *p = [[Person alloc] init]; // 1
7.如何防止block循环引用
1.使用一个用__weak 修饰的值指针保存对象
2.或者使用Block_copy(myBlock)
ARC
//Person *p = [[Person alloc] init]; // __weak Person *weakP = p; NSLog(@"retainCount = %lu", [p retainCount]); void (^myBlock)() = ^{ NSLog(@"p = %@", p); // 2 // NSLog(@"p = %p", weakP); NSLog(@"block retainCount = %lu", [p retainCount]); }; Block_copy(myBlock);//将block对象转移到堆中 myBlock(); [p release]; 1
MRC
__block Person *p = [[Person alloc] init]; // 1