一、ARC
(一)基本原理
项目:ARC0427
1.MRC:Manual Reference Counting 手动引用计数
手动添加retain、release、autorelease、super dealloc
2.ARC:Automatic Referenc Counting 自动引用计数
ARC内存管理原则:
1)有强引用指针指向的对象,不会被释放掉
2)若没有,就会被立刻释放。
3.关键字的使用
1)系统在编译时自动添加retain、release、autorelease、super dealloc
2)禁用retain、release、autorelease、super dealloc
使用新关键字strong、weak、unsafe_unretain(不常用)、__bridge
(1) strong:强引用,会对对象引用计数+1。出了作用域,就会被释放。
(2) weak,(不常用)unsafe_unretain:弱引用,对引用计数无+-。
weak:立即被释放。当对象释放,指针会指向nil,不会造成程序崩溃
unsafe_unretained(不常用):当对象释放,指针仍指向被释放对象的内存,程序会崩溃
(3) __bridge:用于 对OC类型与CF类型 互相转换时的内存管理。
特点:
①在ARC中使用
②不会改变ownership(内存管理权限)
方法:CFBridgingRetain
特点:交换管理权限
注意:声明变量时,默认是strong
4.Foundation 和 CoreFoundation
1)概念
Foundation框架:定义了常用的数据类型(如OC对象 NSString、NSData、NSSet等)。
CoreFoundation框架:定义了与系统底层API打交道的数据类型(CF开头的类型)。
2)区别
OC类型 与 CF类型 在内存结构上是相同的,即同一块内存地址上有两个不同的名字(NS,CF)
3)转换
ARC下,OC与CF 要使用关键字__bridge 进行转换
MRC下,OC与CF 可直接进行 强制类型转换
(二)
项目:ARC_More0427
1.__autoreleasing:不常用,系统会自动添加
2.@autoreleasepool{}:不常用,可以替换 MRC 中的 NSAutoreleasePool
在局部大量创建自动释放的对象时(如for循环),会使用自动释放池。
3.移除通知:自定义类的对象被注册为监听者时,当该对象被释放时,在该类的dealloc方法中移除通知
4.局部、实例、全局变量
1)局部变量:出了作用域就会被释放
2)实例变量:dealloc中释放
3)全局变量:程序退出时系统自动收回
在整个应用程序中都可以使用,程序退出时,才被释放。系统管理内存。
//①声明:
#import "AppDelegate.h"
NSString *text = @"全局变量";
//②引入:
#import "ViewController.h"
extern NSString *text;
5.属性关键字的使用
1)基本数据类型:assign(或省略)
2)字符串:copy
3)对象:strong(等同于MRC中的retain)
4)代理:weak(防止循环引用)
5)控件
①拖拽:默认为weak(也可以使用strong,但没有必要)
原因:self.view已经使用了strong关键字,所以没有必要对拖拽的控件使用strong,用weak即可。
②手动:strong
6.ARC与MRC的混编
1)ARC环境下:使用第三方类库(不支持ARC),在每个文件上加 -fno-objc-arc
2)MRC环境下:使用第三方类库(只支持ARC),在每个文件上加 -fobjc-arc
举例:
weak
__weak UIView *view1 = [[UIView alloc]initWithFrame:CGRectZero];
NSLog(@"1.view1 = %@",view1);//被立即释放
{
UIView *view2 = [[UIView alloc]initWithFrame:CGRectZero];//strong
view1 = view2;//只要有一个strong,view1就不会释放
NSLog(@"2.view1 = %@",view1);
}//view2被释放,即view2 = nil;view1也为nil
NSLog(@"3.view1 = %@",view1);
二、Block
(一)
项目:Block_Define0427
一、局部block对象 定义格式
1.声明
void(^blockName)(parameter list)
①无参无返回值
②有参无返回值
③有参有返回值
float(^calculateBMI)(float,float);
2.实现
blockName = ^(parameter list){ myCode };
calculateBMI = ^(float weight,float height)
{
float BMI = weight / (height *height);
return BMI;
};
3.调用
blockName(parameter list);
float bmi = calculateBMI(70,1.7);
(二)block内部使用外部变量
项目:Block_UseOutPamater
1.局部变量
1)普通局部变量
相当于copy了一个新的变量,值和原来的一样,
block内只读,与外部的i是两个不同的变量
int i = 1;
2)使用__block关键字
block内可修改,与外部的i是同一变量
__block int block_i = 1;
2.实例变量和静态变量
block是从变量所在的内存地址中读取最新的值
可修改
(三)
项目:Block_MRC_Memory
1.MRC下的内存分配
1)不使用外部变量
NSGlobalBlock类型,分配在全局变量区,由系统收回
2)使用外部变量
NSStackBlock类型,分配到栈区
该block出了作用域,就由系统释放。
3)对分配在栈区的block进行Block_copy操作
NSMallocBlock类型,分配在堆区
程序员只要不调用Block_release(...)方法,block就始终存在
2.ARC下的内存分配
系统会对栈上的block进行一次copy,拷贝到堆区,由NSStackBlock--->NSMallocBlock
使用外部变量
NSMallocBlock类型
(四)
项目:Block_MRC_Memory
UIView *view = [[UIView alloc]initWithFrame:CGRectZero];
void(^block1)() = ^()
{
view.backgroundColor = [UIColor redColor];
};
Block_copy(block1);//copy方法只对栈区的block有用
使用Block_copy使block1变为堆区
分配在堆上的block会对外部变量的引用计数+1
当block释放时,它内部使用的外部变量的引用计数会随之-1
造成循环引用:
block释放时,self.retainCount会-1
self释放时,block才会释放(在self的dealloc方法中释放)
防止循环引用:
在MRC环境中,使用__block修饰外部变量
在ARC环境中,使用__weak修饰
(五)
项目:Block_TransformValue0427
1.遍历
1)遍历数组
NSArray *array = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8"];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"obj%d = %@",idx,obj);
if (idx == 4)
{
*stop = YES;//停止循环
}
}];
2)倒序遍历
[array enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
}];
2.传值
测试:alertView传值,用block