标签:pre 释放 rate dealloc 说明 符号 不同 复制 __strong
iOS的内存管理和引用计数规则
内存管理的思考方式
ARC有效时,id类型和对象类型必须加上所有权修饰符,一共有四种
__strong
id和对象类型如果不加所有权修饰符那么默认为__strong类型
id obj = [[NSObject alloc]init]
id __strong obj = [[NSObject alloc]init]
//以上两种在ARC有效情况下是相同的
//ARARC
{
id __strong obj = [[NSObject alloc]init]
}
//ARC无效时
{
id obj = [[NSObject alloc]init]
[obj release]
}
//ARC无效时执行release操作
__strong修饰符表示对对象的强引用,持有强引用的变量在超出其作用域时被废弃,它强引用的对象也会被释放
含有__strong修饰的变量,不仅仅在作用域上,在赋值上也能正确管理对象的生命周期
__weak
__unsafe_unretained
__autoreleasing
属性声明的属性修饰符与所有权修饰符之间的关系
属性修饰符 | _unsafe_unretained |
---|---|
assign | _unsafe_unretained |
copy | _strong(指针变量指向的是新的被复制的对象) |
retain | _strong |
strong | _strong |
unsafe_unretained | _unsafe_unretained |
weak | _weak |
为属性添加各种修饰符就相当于给变量添加各种对应的所有权修饰符
@property (strong) id obj;
--------------------------
id __strong obj = [[NSObject alloc]init]
ARC的规则
Block
block是什么
//一句话概括,block是带有自动变量的匿名函数
^(int param){
NSLog(@"%d",param);
}
-------------------------------------
//上面的为简写的,完整的block形式为
//^返回值类型 (参数列表){表达式}
^void (int param){
NSLog(@"%d",param);
}
//完整形式的block语法与C语言函数定义相比,仅有两点不同
//1.没有函数名---没有函数名因为它是匿名函数
//2.带有"^"符号---^是插入记号,方便查找
block的返回值类型可以省略,省略返回值类型时
block的参数类型也可以省略
^(void)(void){expression}
-------------------------
^{expression}
//C语言的函数指针的写法
int func(int a){
printf("%d",a);
}
int (*funcptr)(int) = &func //将func函数的地址赋值给函数指针funcptr
//block的写法
int (^blk)(int a); //仅仅是将c语言函数指针的"*"更换成了"^"
block类型变量与c语言变量的用法完全相同,可以作为以下用途使用
block变量的使用
//将block赋值给block变量
int (^blk)(int) = ^(int){};
//将block变量赋值给block变量
int (^blk1)(int) = blk;
//两个block变量互相赋值
int (^blk2)(int);
blk2 = blk1;
//在函数参数中使用block类型变量可以向函数传递block
void func((int)(^blk)(int));
//在函数返回值中使用block可以将返回值指定为block
void func(){
return ^{return;};
}
//使用typedef定义block
typedef (int)(^blk)(int); //定义一个block,后面该block的类型就为blk
//通过block类型变量调用block与在c语言中通常的函数执行没什么区别
blk func(blk block,int rate){
return blk(rate);
}
//这里blk截获的是Array对象的实例指针,通过这个实例指针调用该对象的方法是完全没问题的,但是如果向Array指针赋值的话就会编译错误(可以用__block解决)
id Array = [NSMutableArray new];
void (^blk)(void) = ^{
id obj = [NSObject new];
[Array addObject:obj];
};
在block中如果需要改变被截获的外部变量的值,可以使用__block说明符(__block存储域类说明符)来解决
block代码转换为cpp代码分析(待完善)
//block对外部变量捕获的原理,使用cpp代码查看
//这里写一个block捕获外部变量val的值
int val = 10;
void (^blk)(void) = ^{
printf("%d",val);
};
//block本质也是一个OC的对象,oc对象都是结构体,其中含有指向父类的isa指针
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int val;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val, int flags=0) : val(_val) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
//这里使用clang -rewrite-objc将.m代码转换成.cpp代码,这里的_cself是block的自身的结构体指针,可以看到在block的函数中是将val重新创建了一个变量进行输出
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
int val = __cself->val; // bound by copy
printf("%d",val);
}
三种block的形式
NSConcreteGlobalBlock(全局Block,存放在全局区[数据区])
NSConcreteStackBlock(栈Block)
NSConcreteMallocBlock(堆Block)
配置在全局区的block在变量作用域外也可以通过指针安全的访问,但是配置在栈上的block一旦其作用域结束就会被系统回收
Block提供了将Block和__Block变量复制到堆上的方法来解决这个问题
复制到堆上的block将类对象NSMallocBlock赋值给isa指针
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _val, int flags=0) : val(_val) {
//注意这里就是讲isa指针指向堆Block
impl.isa = &_NSConcreteStackBlock;
}
};
iOS的内存管理和引用计数规则、Block的用法以及三种形式(stack、malloc、global)
标签:pre 释放 rate dealloc 说明 符号 不同 复制 __strong
原文地址:https://www.cnblogs.com/chenprice/p/12861306.html