Block使用的简单总结

一.Block简单的使用

1.block当作参数来传递

如下定义一个没有返回值无参数的block,并把它作为参数,让系统调用,注意:这里是系统在调用,不是我们调用

那么为什么需要把block当作参数去使用呢?

这就引出了block这个时候的使用场景:当自己封装一个类的时候,有些事情由外部决定,但什么时候做由内部决定,(即内部决定执行时间,外部传入具体做些什么)——这个时候就可以使用block来作为参数

2.block当作返回值来使用

如下代码,test为方法名,void(^)()这就是block的类型,这样就可以这样使用,其中的的self.test是相当于属性的get方法,后面再加一个()就相当于执行block.

同时时还可以将这个block给相同类型的bock赋值.如下代码所示.

所以myBlock后加一个小括号就是执行,这样就能理解为什么上面self.test加一个小括号就是执行.——这让我联想到swift里执行函数都是点点点,并且加上()就是创建对象执行函数等等,原来都是这么的类似....

block当返回值使用思想:链式编程,把方法调用通过语法链接起来,可读性非常好

下面简单来演示一下用Block来进行链式编程

创建一个类继承NSObject命名为AddTool,即到时我们要用它来进行链式累加,它的.h文件里如下

它的.m文件如下:

然后在ViewController类里进行调用如下

运行起来,打印结果为,OK完成!

二.Block逆传值的使用

Block可以用于控制器界面间逆向传值.使用方法是这样:控制器B传值给控制器A, 那么要在控制器B中的头文件.h声明一个Block属性, 并且在控制器B的.m文件中执行这个Block.

代码表示如下:

    • 在B的头文件中

@property (nonatomic,strong) void(^myBlock)(NSString *);

说明:这里定义了一个无返回值,参数为NSString *的Block,Block的名字为myBlock,这就类比声明一个函数void test(int);——无返回值,参数为int,函数名为test.

如果是创建一个int返回值的block将上面的void改为int

且这里的Block类型为strong类型,关于Block的修辞策略后面再讲.

    • 在B的.m文件中这样使用

if (_myBlock) {

_myBlock(@"1234567");

NSLog(@"%@", str);

}

说明:这里的if是对Block先进行判断,作用是判断Block是否已经分配好内存,如果定义完成就执行,并传入了一个字符串参数

如果block有返回值,那么可以用一个值来接收它的返回值如int num = _myBlock(@“1234567”);

    • 在A的.m文件中

先importB的头文件,再创建一个B的具体对象如下为myVC,然后

myViewController *myVC = segue.destinationViewController;
    myVC.myBlock = ^(NSString *str){

NSLog(@"%@", str);

};

说明:如果block有返回值,那需要在Block内部加上一句return才行.如return 10;这样myBlock就有了值,从而B中的num也就有了值.即这个有值的过程是先内部的block有值然后执行完外部才有值.

三.Block的循环引用问题

1.简单循环引用

循环引用的描述:就是当对象不想使用时本应释放,但由于循环强引用,谁也释放不了谁造成内存泄露.

Block发生循环引用的场合:ARC中Block为strong或copy属性,在Block内部使用了当前类的self属性,同时这个类包含了别一个类的Block属性.

举例:还是上面的传值的例子,现假如在A的.m文件的block里使用了self.view.backgroundColor = [UIColor redColor];现在这些对象之间的引用关系如下图所示:

因此这样就就造成了循环引用.

Block内循环引用的解决:

在如下的例子,可以在Block外加上这样一句(如果将typeof用于表达式,则该表达式不会执行。只会得到该表达式的类型。)

__weak typeof(self) weakSelf = self;

或者这样也可以

__weak ViewController *weakSelf = self;

2.复杂循环引用

这个还没遇到过,只是看到有这样用过.....这个后面有时间再分析!

四.Block的内存分析(ARC与非ARC下的验证)

如何验证arc还是非arc,一点点回顾

1.arc中无法调用retain和release,并且dealloc方法不能调用super dealloc.非ARC中super dealloc写在最后面

2.项目 -> build settings -> ARC

ARC的set方法如下,与上次值不相等,就释放旧值,retain新值..所以我们在ARC应尽量用self.这种方式去调用set方法,而不要直接使用下划线,因为会内存泄露.

非ARC中没有weak,没有strong,只有对应的assign和retain

strong与copy:因为上面这里字符串用到了copy,而且上面代码也是ARC下copy内部做的事,也就是它会release旧值,将新字符串name重新copy一份赋值给旧_name.这样当我们改变_name时,不会影响到name.(ps:arc下一般如果不会改变的字符串就尽量用strong,因为省得copy一份出来,相比而言copy更耗性能,对于ARC下使用Block也是如此,不需要copy就用strong就好)

内存5大区

内存分为5大区:堆, 栈, 方法区, 静态区(全局区), 常量区

ps: 全局区和静态区其实是一样的,从内存上来看,全局变量和静态变量都是保存在静态存储区,生命期和程序一样,都是在静态数据区分配内存.在程序结束后回收内存.

  它们之间作用域有所不同,全局变量的作用域是整个项目,静态全局变量是当前程序文件,静态局部变量是当前函数体内.

堆:手动管理内存     栈:代码块一过,系统自动回收对应内存区

首先来了解一下Block,苹果官方文档Block是对象.(因为它是对象,所以用%@格式打印可以看到它的内存分配区),文档描述第一句话如下:

非ARC下:

1.全局区的情况:如下定义一个Block,并将它使用, 它的打印结果为,global表示全局区.全局区表示到处都可以使用.(ps:假如block内部访问static修辞的外部局变量,那么它也是在全局区,关于静态区与全局刚刚上面已经解释过)

2.栈区:如下当Block内访问一个外面的局部变量a,它的打印结果为,stack表示栈区

总结如下:Block的内存分配与它内部访问的变量有关,如果访问的是全局变量,那Block会在全局区;  如果访问局部变量,那Block会分配到栈区.(什么也不访问默认在全局区)

3.堆区:使用copy进行强引用时block会copy一份到堆区

在非ARC环境下用retain修辞Block会有黄色警告,如下图,警告提示最好使用copy

假如现在就用retain,并且在block内访问了一个局部变量a(这个a就写在Block的上面),代码如下,这时发现一运行程序就漰了.(坏内存访问,报错会出现在使用self.Block的地方)

这一点总结:在非ARC下不能用retain引用block,因为这样不会把block放在堆里,它会在栈区,所以代码区一出括号就会销毁,于是会报错.只要使用copy就可以把block放到堆里面.这样block就不会销毁.——所以说block要用copy都是老程序员说的,因为那时没有ARC.

ARC下:

1.全局区:还是如下代码,默认Block还是放在全局区,没访问外部变量就都是在全局区,与是否ARC无关

2.堆:访问一个外部局部变量或对象时,代码如下,它的打印结果,这个malloc分配的内存是表示在堆上.(这有点像ARC下默认一个对象就是强引用,好处是不会一创建就销毁.)

五.Block的内变量的传递与改变

看下面代码,这个很简单,block打印出来肯定是10

值传递

再看如下代码,这个打印出来是5, 虽然block()执行之前a = 10,但,因为a = 5之后就立即被传递进了block,只是还没有执行而已,即内存已配好.而且这时的block是值传递,这时外面更改无法改变里面的值.(如果是指针传递则可以)

指针传递

那么再看如下代码,这个打印结果会是10,原因:只要局部变量生命周期是整个app运行都在,那么就是指针传递

这里加static后,生命周期就与整个程序同存亡了.与全局区一样(这一点上面Block内存分析时分析过了)

下在情况也是指针传递,所以打印出来也会是10

block变量传递总结:如果在block内部访问的是局部变量,那么就是值传递,否则就是指针传递

时间: 2024-10-17 01:55:22

Block使用的简单总结的相关文章

IOS 中block结构的简单用法

自从block出现之后,很多API都开始采用这样的结构,由此可见,block确实有许多优势存在,这里将一些简单用法总结如下: 一.如何声明一个block变量 我们通过^符号来声明block类型,形式如下: void (^myBlock)(); 其中第一个void是返回值,可以是任意类型,中间括号中^后面的是这个block变量的名字,我把它命名为myBlock,最后一个括号中是参数,如果多参数,可以写成如下样式: int (^myBlock)(int,int); 同样,你也可以给参数起名字: in

block的传值简单示例仅供参考,大牛勿喷

#import "ViewController.h" typedef void(^sumBlock)(int s);//声明为一个类型; /** *  用声明的block类型 sumBlock 定义block变量 s,s当做方法sum的一个参数, * *  这样在sum的方法实现里面给这个block变量s的参数传值,这个值就可以在调用 sum方法的地方通过这个block的参数值拿到在sum实现内传递的值 */ - (void)sum:(int)a :(int)b :(sumBlock)

关于block体的简单使用

1:什么是 block 体,具体是什么形式,以及在什么时候使用? a)  Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,从ios4.0开始就很好的支持Block. b)其形式如下: 再次声明:block可以访问和block定义在同一个词法范围里的变量. <span style=""><span class="kwd">{int</span><span class="pln&qu

Block页面传值的简单使用

1.我要实现一个界面一个界面输入框输入的内容在另一个界面显示,实现效果如下图:               2.在第二个界面将block声明为属性,代码如下 3.在点击第二个界面中"Back"按钮的响应方法里将声明的Block传值传出去,代码如下 4.在第一个界面的button按钮的响应事件里面将block实现,代码如下: Block就是如此简单,以后常使用这个

iOS中Block的基础用法

本文简介 本章不会对Block做过多的实现研究.只是讲解基本的用法.纯粹基础知识.结合实际项目怎么去做举例.Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等.用过GCD就知道Block的精妙之处. Block简介 Block是一种比较特殊的数据类型.它可以保存一段代码,在合适的时候取出来调用. Block的修饰 ARC情况下1.如果用copy修饰Block,该Block就会存储在堆空间.则会对Block的内部对象进行强引用,导致循环引用.内存无法释放.解决方法:新建一个

深入理解block

2010年WWDC发布iOS4时Apple对Objective-C进行了一次重要的升级:支持Block.说到底这东西就是闭包,其他高级语音例如Java和C++已有支持,第一次使用Block感觉满简单好用的,但是慢慢也遇到很多坑.本文聊聊ARC和non-ARC下Block使用中的引用循环问题,最近遇到了好几次这种问题,还是深入记录下.先来套题目热热身,貌似能够全部答对的人蛮少的 Block实现原理 首先探究下Block的实现原理,由于Objective-C是C语言的超集,既然OC中的NSObjec

block学习笔记

??????????Block基本使用 block最基本的使用方式,创建 — 调用. 这里的block类型:void(^)()  —> 无返回值 无参数 三种创建block的方式,最常用的是方式三. inlineBlock:快速生成block代码. block作用:保存一段代码,并不是马上执行,需要手动调用 ??Block使用场景(简单阐述) 定义cellItem模型,声明一个block属性 实现快速生成模型类方法 在目标控制器取出模型并初始化数据 当点击cell时,执行block中的代码 ??

[HMLY]10.iOS中block的基础用法

本文简介 本章不会对Block做过多的实现研究.只是讲解基本的用法.纯粹基础知识.结合实际项目怎么去做举例.Block使用场景,可以在两个界面的传值,也可以对代码封装作为参数的传递等.用过GCD就知道Block的精妙之处. Block简介 Block是一种比较特殊的数据类型.它可以保存一段代码,在合适的时候取出来调用. Block的修饰 ARC情况下1.如果用copy修饰Block,该Block就会存储在堆空间.则会对Block的内部对象进行强引用,导致循环引用.内存无法释放.解决方法:新建一个

Variable &#39;bop&#39; is uninitialized when captured by block

代码: - (void)doTest { NSBlockOperation * bop = [NSBlockOperation blockOperationWithBlock:^{ if (!bop.isCancelled) { // ... // doSomething } }]; [mQueue addOperation:bop]; } 这段代码是有明显问题的,如果用Analyze来检查的话,就会有警告Variable 'bop' is uninitialized when captured