1:block的循环引用问题最主要记住两点:
如果【block内部】使用【外部声明的强引用】访问【对象A】, 那么【block内部】会自动产生一个【强引用】指向【对象A】
如果【block内部】使用【外部声明的弱引用】访问【对象A】, 那么【block内部】会自动产生一个【弱引用】指向【对象A】
2:
#import "ViewController.h" #import "XMGPerson.h" @interface ViewController () @property (nonatomic, copy) int (^sumBlock)(int, int); @property (nonatomic, assign) int a; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self test5]; /* 如果【block内部】使用【外部声明的强引用】访问【对象A】, 那么【block内部】会自动产生一个【强引用】指向【对象A】 如果【block内部】使用【外部声明的弱引用】访问【对象A】, 那么【block内部】会自动产生一个【弱引用】指向【对象A】 */ } /** * 不可行 */ - (void)test6 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 XMGPerson *strongP = weakP; NSLog(@"block1 -- %@", strongP.name); dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ // block2 NSLog(@"block2 -- %@", weakP.name); }); }; p.block(); } /** * 可行 */ - (void)test5 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); XMGPerson *strongP = weakP; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ // block2 // NSLog(@"block2 -- %@", weakP.name); NSLog(@"block2 -- %@", strongP.name); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // block3 NSLog(@"block3 -- %@", strongP.name); }); }); }; p.block(); } /** * 不可行 */ - (void)test4 { XMGPerson *p = [[XMGPerson alloc] init]; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ // block2 NSLog(@"after-----------%@", p.name); }); }; p.block(); } /** * 不可行 */ - (void)test3 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); XMGPerson *strongP = weakP; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // block2 NSLog(@"after-----------%@", strongP.name); }); }; p.block(); } /** * 可行 */ - (void)test2 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); XMGPerson *strongP = weakP; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // block2 NSLog(@"after-----------%@", strongP.name); }); }; p.block(); } - (void)test1 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ NSLog(@"-----------%@", weakP.name); }; } #pragma mark - 其他 - (void)test:(int (^)(int, int))sumBlock { } - (void)run:(int)a { } - (void)testBlock { [self test:^(int a, int b){ return a + b; }]; void (^block)() = ^{ NSLog(@"-------"); }; block(); int (^sumBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; }; sumBlock(10, 10); int a = 10; /* 返回值类型 (^block的变量名)(形参类型列表) = ^(形参列表) { // block代码 }; block的变量名(实参列表); */ } @end
总结:1:block的定义:1:block以属性定义的时候,用copy修饰,
@property (nonatomic, copy) void (^block)();无参数无返回值,因为block默认是在堆里,需要将堆中的block,copy到栈中才能使用 2:block的非属性定义:1:无参数无返回值:
其中 void (^block)() 表示声明一个名称为block的block,block的类型表示为:void (^)(),右边的为block任务的代码块,
block();表示调用block,右边为左边的block赋值
void (^block)() = ^{ NSLog(@"-------"); }; block(); 2:有参数有返回值的block:左边int (^sumBlock)(int, int)定义一个有参数有返回值的block:sumBlock,而右边的block给左边的block赋值,写法:参数写在^(int a,int b)其中ab为block的参数,返回值写在block的代码块中。
sumBlock(10, 10);调用block,并未block传递参数
^(int num1, int num2){ return num1 + num2; };
int (^sumBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; }; sumBlock(10, 10);
3:block作为参数传递:1: block作为参数传递 - (void)test:(int (^)(int, int))sumBlock,实现该方法,调用block传递参数 2:在外部调用test方法,其中ab就为传递的参数,
[self test:^(int a, int b){
NSLog(@"%d",a+b);
return a + b;
}];
- (void)test:(int (^)(int, int))sumBlock
{
sumBlock(2,1);
}
4:1:block的循环引用:XMGPerson alloc init 之后在内存中产生一个对象,name 和 block是该对象的属性(因为用copy修饰,也就相当于强引用),则该对象会对这两个属性分别有一个强引用,创建完对象之后,有一个强指针p指向该对象(指针里存放的是对象的地址,变量创建之后无论是全局变量还是局部变量都会有一个强引用),__weak那部分代码是将强指针p的地址复制给一个弱指针weakSelf,此时弱指针weakSelf会有一个弱引用指向person对象,p.name = @"JACK";此时name属性会对jack有一个强引用,block会对赋值的block有一个强引用。此时不会立即调用block代码块中的任务,但是此时会检测block代码块中有无引用外部变量(即使是外部无引用,在after中引用了,也算block中引用了外部变量,此时会对访问的该对象有一个强引用或是弱引用,代码块中有引用weakP,所以会产生一个弱引用),再执行代码调用block,执行block代码块中的任务,将一个弱引用weakP指针赋值给一个强引用,此时block代码块中的strongP会对person对象有一个强引用,在执行gcd延迟函数,此时会产生延迟函数的block块,会检测延迟函数中有无引用外界的变量,有引用了strongP,则会产生一个强引用指向person对象,此时的代码块不立即执行(但是系统会有一个强指针指向该代码块,如图2),此时会执行到方法结束,强指针p销毁,弱指针weakp销毁,strongP执行完销毁,但此时block2还指向person对象,所以person对象不会销毁,能打印出name 2:像类似于GCD的延迟函数在block中,想要保住对象使其不备销毁,就在block中定义一个强引用指向就可以了
时间: 2024-10-26 10:18:23