聊聊block
block本质
- block本质上也是一个OC对象,它内部也有个isa指针
- block是封装了函数调用以及函数调用环境的OC对象
如下例子 脑海中要有此图。
一个block 底层实现block 就是一个对象, 有一个isa指针, funcptr 存放代码地址, 有外部局部变量
补充内存分布知识:
全局变量 存放数据段,
局部变量 栈区间
实例对象 堆区间
类对象 数据段 >
block类型
block 内存其实在栈上的, 但我们常常需要对其持有长时间,用copy修饰。 从栈区间拷贝到堆区间。栈区间自动释放后, 不会影响堆区间。
block 类型
在ARC模式下 编译器会自动将栈上的block内存copy到堆区间上.
1. block作为函数参数返回。
2. 被 strong指针修饰。
3 . GCD 参数
4. 作为Cocoa API 中方法名有usingBlock方法参数时
-
栈空间上的block 不能持有外部的对象。不能保住对象的命
堆空间上的block 可以引用外部对象。 retain计数+1,release -1 可以 保住对象的命 -
如果block 在栈上, block内部不会对外部的auto变量强引用
-
在堆上, block内部自动进行copy工作 从底层结构体 main_block_desc_0 内部就可以看出 会自动调用一个 main_block_copy 调用一个 block_object_assgin会根据atuo变量的修饰符(__strong __weak ,_unsafe_unretained)做出操作 类似于retain(形成强引用, 若引用)。
-
如果block从堆中移除, 会调用dispose函数
dispose函数内部会调用_block_object_dispose函数, 会自动释放引用的auto变量, 类似于release.
为什么我们常用weak修饰block呢 也就是说。 当对象想死的时候 。 block不会强行占有对象。 对象可以死去。哈哈哈
- oc 转C++命令
clang -x objective-c -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk main.m
** 为什么在block内部不能修改局部外部变量呢?
内部结构体 属性age 和block 在两个函数里。 在block函数里访问不到外部局部变量
int main(int argc, const char * argv[]) {
@autoreleasepool {
int age = 10;
tsBlock block = ^{
//age = 20;
NSLog(@"age is %d", age);
};
block();
}
return 0;
}
外部局部变量无法修改
-
1.static 修饰局部变量(一般不采用.内存无法释放) 可以在如下图片中看到 age前边加了指针 就可以访问了
staic 修饰后
__block int age = 10;
tsBlock block = ^{
age = 20;
NSLog(@"age is %d", age);
};
block();
}
-
2.__block 修饰局部变量. 可以解决无法修改局部变量问题
看内部c++ 代码. 多了一个包装结构体block
block内部有一个指针 指向结构体, 通过指针找到那个结构体内存,
把结构体里的变量改掉.
__block修饰后
3.block 修饰对象.
int main(int argc, const char * argv[]) {
@autoreleasepool {
__block MJPerson *p = [[MJPerson alloc] init];
tsBlock block = ^{
NSLog(@"%@", p);
};
block();
}
return 0;
}
修饰对象
block
block
循环引用问题
int main(int argc, const char * argv[]) {
@autoreleasepool {
MJPerson *p = [[MJPerson alloc] init];
p.block = ^{
NSLog(@"%@", p.name);
};
NSLog(@"111111");
}
return 0;
}
[循环引用)]
循环引用
block内部结构体生成一个强引用的指针 指向类对象, 对象里边有个变量block 会访问 block. 也就是有个强引用指针.
本质:两个强引用, 你引用我. 我引用你. 导致无法释放
解决循环引用问题
不会产生强引用, 不安全, 指向的对象销毁, 指针存储的地址值不变.
1. __unsafe_unretained MJPerson *p = [[MJPerson alloc] init];
不会产生强引用.指向对象销毁时候,会自动让置为 nil
2. __weak MJPerson *weakPerson = p;
p.block = ^{
NSLog(@"%@", p.name);
};
NSLog(@"111111");
解决循环引用 MRC 解决block3.说说第三种用block解决方式 对象 - block - block变量. block变量里边有一个指针指向对象. 形成三者紧密联系. 当我们把block变量里边的这个对象指针置位nil. 就解决了引用. 但不是最好的方式.
block 本质是什么
-封装了函数调用以及调用环境的oc对象
__block修饰符 干了什么
- __block可以用于解决block内部无法修改auto变量值得问题
不能修饰全局变量,静态变量(static)
-编辑器会将__block变量包装成一个对象
block属性修饰符词为什么是copy,使用block哪些注意点
- copy 把内存拷贝到堆上.
block在修改NSmutablearray用不用加上 __block
- 不用. 加上后.反而内部结构变复杂.