对iOS-Block的理解

在OC中,所谓的block:就是一个代码块,我们可以理解为类似一个方法。

关于Block的内存管理:

都说可以把Block视为一个方法,而所谓方法,在被调用的时候是从硬盘到内存,然后去执行方法的代码,执行完就消失;所以方法的内存不需要我们管理,也就是说,方法是在内存的栈区。

同样的,block不像OC中的类对象(OC中的类对象是存放在堆区的),block也存在于栈区;当我们使用block作为一个对象的属性时,我们会使用copy修饰它,因为正常情况下block是在栈区,我们没办法控制它的消亡;当我们使用copy修饰的时候,系统会把该block的实现拷贝一份到堆区,这样我们对应的属性,就拥有该block的所有权,就可以保证block代码块不会提前消亡。



PS:在Block使用过程中应该要注意的事情

我在实现block的时候,可能会用到block的外部变量(block大括号之外);我们知道,局部变量(非静态)是不能在外部使用的,而block又类似一个方法,那为什么block可以使用外部变量呢?

其实:这是因为OC是一种运行是语言,我们写的OC代码最终都会被转换成C语言的代码去执行;我们可以通过运行时代码发现,系统会把使用到的外部变量通过参数列表传递给block,也就变成block内部的局部变量,也就可以使用了。

但是,在参数传递的过程中。

对于基本数据类型的外部数据来说,这时候系统默认传递的仅仅是值,并不能对参数进行根本意义上的修改,也就是说不能对这些参数进行修改,只能读取;如果想修改这些外部变量,则要使用__block来修饰这个变量;这样一来,我们在传递参数的时候 ,就不仅仅是传递外部变量的值,而是传递外部变量的地址,我们就可以修改这些外部变量的值了。

__block int a =10;  //用__block修饰之后,系统会传递a的地址(&a)

    _block = ^{

        a +=20;

        NSLog(@"a = %d",a);//有地址,当然就可以修改a的值了。此时a的值是30

};

对于对象类型的外部变量来说,这时候系统默认传递的传递的是地址;同时默认对该对象进行一次强引用。系统进行了强引用,而block又不管内存管理(只做了强引用,并没有做释放操作),这个时候就会造成内存泄露。所以,我们在使用对象的时候,在MRC下,都会使用__block修饰,在ARC下,使用__weak修饰,这样一来,系统在传递的时候就不会对该对象进行强引用,避免了内存泄漏。

- (void)viewDidLoad { 

[super viewDidLoad]; 

UIView *view = [[UIView alloc] init]; 

__weak typeof(view)_view = view;//_view和view指向同一块内存,而_view是弱引用,view的retainCount还是1. 

_block = ^{ 

//view.frame = CGRectMake(0, 0, 100, 100);//在block内部使用view对象,系统会对view强引用,此时会造成内存泄漏。

_view.frame = CGRectMake(0,0,100,100);

 };

}

以上内容参考链接

猜你喜欢

转载自blog.csdn.net/weixin_34090643/article/details/90991557