iOS 三种类型的Block

Block 的copy 操作

Block 其实来讲有三种类型

  • 全局块 NSConcreteGlobalBlock

  • 栈块 NSConcreteStackBlock

  • 堆块 NSConcreteMallocBlock

  • 全局块存储在全局内存中,相当于单例

  • 栈块存于栈内存中,超出其作用域则马上进行销毁

  • 堆块存在于堆内存中,是带一个引用计数的对象,需要自己进行内存管理

1> Block 不访问外界变量(包括堆中和栈中的变量)
既不存在栈又不在堆中,在代码段中ARC和MRC下都是如此,此时为全局块。

2 > Block 访问外界变量

ARC 环境下:访问外界变量的 Block 默认存储在堆中(实际是放在栈区,然后ARC情况下自动又拷贝到堆区),自动释放。

自己的理解:
至于为什么要用copy 修饰 block,说直白一点,就是为了延长block 的生命周期,我们使用的block 本身是存在于栈上的,如果不适用copy,函数调用结束的时候,block 就会被销毁。
函数调用结束,调用函数开辟的栈内存就会被回收,保存在函数栈上的block 自然而然就被销毁了,我们再使用的时候,就会空指针异常。

如果是堆中的block,也就是copy 的 block,他的生命周期是随着对象的销毁而结束的,只要对象不销毁,我们就可以调用到堆中的block。


@interface ViewController ()
// 定义一个block
@property (nonatomic,copy)void(^myBlock)(void);

@end

@implementation ViewController

- (void)viewDidLoad {
	[super viewDidLoad];
	// Do any additional setup after loading the view, typically from a nib.
	
	//1  全局块 存储在代码区 NSConcreteGlobalBlock
	// 不访问外部的变量就是全局块
	void (^myBlock1)(void) = ^() {
		NSLog(@"全局块");
	};
	myBlock1();
	NSLog(@"%@",myBlock1);

	
	
	//2  存储在栈区域 访问外部变量, 但是没有进行copy,函数作用域结束
	// NSConcreteStackBlock
	int q = 15;
	void(^myBlock2)(void) = ^(){
		NSLog(@"栈块 --%d",q);
	};
	
	myBlock2();
	NSLog(@"%@",myBlock2);
	//3 堆块
	// NSConcreteMallocBlock
	int p = 25;
	void(^myBlock3)(void) = ^(){
		NSLog(@"堆块--%d",p);
	};
	
	// 进行一次copy 操作
	[myBlock3 copy];
	
	myBlock3();
	NSLog(@"%@",[myBlock3 copy]);
	
	[self test];
	// 到这一行 test 函数中所有存储在栈区的变量都会进行销毁,如果myBlock 使用
	// assign 进行修饰的话,没有把block copy到堆内存中的话,在下面的代码再进行访问的话,就会造成问野指针访问. EXC_BAD_ACCESS 错误
	
	// 所以要使 copy 属性进行修饰
	self.myBlock();
}


- (void)test
{
	int a = 10;
	[self setMyBlock:^{
	
		NSLog(@"myblock--%d",a);
	}];
	
	NSLog(@"test--%@",self.myBlock);

}


- (void)didReceiveMemoryWarning {
	[super didReceiveMemoryWarning];
	// Dispose of any resources that can be recreated.
}

你可能感兴趣的:(iOS知识了解)