一、窥探本质
1、看代码(ARC环境)
#import <Foundation/Foundation.h>
#import "Person.h"
typedef void (^Block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
Block block;
{
Person *person = [[Person alloc] init];
person.age = 10;
block = ^{
NSLog(@"--%d",person.age);
};
}
NSLog(@"---");
}
return 0;
}
打印结果:
2022-01-02 09:38:21.647450+0800 block[47069:12449027] —
2022-01-02 09:38:21.648386+0800 block[47069:12449027] 释放Person对象
Program ended with exit code: 0
- Person对象被强引用没有被释放
2、MRC环境下
#import <Foundation/Foundation.h>
#import "Person.h"
typedef void (^Block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
Block block;
{
Person *person = [[Person alloc] init];
person.age = 10;
block = ^{
NSLog(@"--%d",person.age);
};
[person release]; // MRC环境下,需要手动释放一次
}
NSLog(@"---");
}
return 0;
}
打印结果:大括号一结束,Person就销毁了
2022-01-04 11:37:14.050683+0800 block[67246:3606713] Person–销毁
2022-01-04 11:37:14.051047+0800 block[67246:3606713] —
Program ended with exit code: 0
说明:
1、此刻的block是在栈里面(点我查看block类型分析)
2、当把block放到堆里面去,增加一次copy:
- __weak问题解决
在使用clang转换OC为C++代码是,可能会报错:
cannot creat __weak reference in file using manual reference
解决方法:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-8.0.0 main.m
看下面的代码👇🏻
#import <Foundation/Foundation.h>
#import "Person.h"
typedef void (^Block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
Block block;
{
Person *person = [[Person alloc] init];
person.age = 10;
block = [^{
NSLog(@"--%d",person.age);
} copy]; // 增加一次copy,把block放到堆里面去
[person release]; // MRC环境下,需要手动释放一次
}
NSLog(@"---");
}
return 0;
}
打印结果:2022-01-04 11:44:49.351354+0800 block[67560:3611589] —
Program ended with exit code: 0
说明:
此刻block在堆里面,但是person没有被释放
小结:
当block在栈空间的时候,不会对堆空间的对象持有;当block在堆空间的时候,会对堆空间的对象持有。
3、对象类型的auto变量
-
当block内部访问了对象类型的auto变量时
1、如果block是在栈上,将不会对auto变量产生强引用
2、如果block是被拷贝到堆上(a) 会调用block内部的copy函数
(b) copy函数内部会调用_Block_object_assign函数
© _Block_object_assign函数会根据auto变量的修饰符(__Strong、__weak、__unsafe_unretain)做出相应的操作,类似于retain(形成强引用、弱引用)
3、如果block从堆上移除
(a) 会调用block内部的dispose函数
(b) dispose函数内部会调用_Block_object_dispose函数
© _Block_object_dispose函数会自动释放引用的auto变量,类似于release
函数 | 调用时间 |
---|---|
copy函数 | 栈上的Block复制到堆时 |
dispose函数 | 堆上的Block被废弃时 |
4、释放时间
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
Person *person = [[Person alloc] init];
__weak Person *weakPerson = person;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"强引用--p--%@",person);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"弱引用--p--%@",weakPerson);
});
});
NSLog(@"开始点击");
}
打印:
2022-01-04 17:19:23.200688+0800 02-kvc[82973:3816167] 开始点击
2022-01-04 17:19:24.294069+0800 02-kvc[82973:3816167] 强引用–p--<Person: 0x600002017820>
2022-01-04 17:19:24.294171+0800 02-kvc[82973:3816167] Person–释放
2022-01-04 17:19:26.446509+0800 02-kvc[82973:3816167] 弱引用–p--(null)
5、block修饰
#import <Foundation/Foundation.h>
#import "Person.h"
typedef void (^Block)(void);
int main(int argc, const char * argv[]) {
@autoreleasepool {
// array不需要加__block修饰
// 是拿这个指针来用,不是对他进行赋值
NSMutableArray *array = [NSMutableArray array];
__block int age = 10;
__block Person *person = [[Person alloc] init];
Block block = ^{
[array addObject:@"123"];
age = 20;
person.age = 3;
};
block();
}
return 0;
}
- 转成C++
struct __Block_byref_age_0 {
void *__isa;
__Block_byref_age_0 *__forwarding; // 这个指针指向自己
int __flags;
int __size;
int age;
};
struct __Block_byref_person_1 {
void *__isa;
__Block_byref_person_1 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
Person *__strong person;
};