Objective-C中的Block(闭包)
学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西。学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也支持闭包, 也就是OC中所提到的Block。 到底什么是闭包或者block呢?用大白话说就是匿名函数,也就是在函数中可以包含这函数。就是在函数中可以定义匿名函数然后在函数中调用。学习OC中的block之前也小担心一下,Block在OC中属于高级的部分,心里有又有个疑问:学起来难不难?看过Block的部分,感觉Block挺好理解的,用起来也挺顺手的,Block没我想象中的那么难理解。
废话少说,学习一门新的编程语言是少不了代码量的支持的,所以代码是少不了的。下面就通代码来认识一下OC中的block的使用。
Block基础部分
1.Block的声明
Block的定义和函数的声明差不多,就是把函数名改成(^blockName)即可。下面是block声明的代码。
有返回值的
|
1
|
int (^sumBlock) (int, int); |
无返回值的
|
1
|
void (^myBlock)(int, int); |
2.给block块赋值
给声明好的block,赋值。block的值就是个函数体,给block块赋值有两种方式,一个在声明的时候赋值,一个是先声明在赋值。
先声明再赋值
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
//代码块的声明void (^myBlock)(int, int);//给代码块赋值myBlock = ^(int a, int b){ //test ++; //报错 NSLog(@"main_test = %d", test); //blockVar++不报错; blockVar ++; NSLog(@"blockVar = %d", blockVar); int sum = a + b; NSLog(@"a + b = %d", sum);}; |
在声明的时候赋值
|
1
2
3
4
5
|
int (^sumBlock) (int, int) = ^(int a, int b){ int sum = a + b; return sum;}; |
3.调用block
block的使用和普通函数的使用相同,调用方法如下:
|
1
2
|
//调用代码块并接收返回值int sum = sumBlock(20, 30); |
4.把block当做参数传入函数
|
1
2
3
4
5
6
|
//把代码块作为函数参数void blockFunction(int (^myBlock)(int, int)){ int sum = myBlock(10,20); NSLog(@"fun_sum = %d", sum);} |
5.在代码块中使用局部变量和全局变量
在block中可以和对全局变量进行访问和修改,但对局部变量只可以访问,若想修改的话,我们可以在声明局部变量的时候加上关键字__block
代码如下:
|
1
|
__block int blockVar = 0; |
Block进阶 参考博客:http://www.cnblogs.com/NarutoYq/
下面的这些内容是参考上面的博客进一步学习的Block的内容,代码是参考这上面的博客自己写的,也就是说下面的东西算是伪原创吧。小伙伴们如果没大看懂下面的东西,请去上面的博客中进一部的了解一下block.
1.局部变量可变对象和不可变对象在block中的引用
下面会提供一部代码,这部分代码的功能是定义两个局部变量,一个是可变对象,一个是不可变对象,然后再定义一个Block, 在block中引用两个局部变量。上面提到了在代码块中可以引用局部变量但是不可以更改其值,除非在声明的时候加上__block关键字。
测试代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
void blockTest1(){ //定义两个变量一个是可变的一个是不可变的 NSString *str1 = @"str1"; NSMutableString *str2 = [NSMutableString stringWithFormat:@"str2"]; //初始值 NSLog(@"两个字符串的初始值和初始地址"); NSLog(@"str1 = %@, str1_p = %p", str1, str1); NSLog(@"str2 = %@, str2_p = %p", str2, str2); //定义block在block中输出连个变量的值和参数 void (^myBlock) () = ^() { NSLog(@"******************************************"); NSLog(@"在block块中输出局部变量的可变和不可变变量"); NSLog(@"str1 = %@, str1_p = %p", str1, str1); NSLog(@"str2 = %@, str2_p = %p", str2, str2); }; //修改前赋值 str1 = @"str1_update"; [str2 appendString:@"_update"]; NSLog(@"******************************************"); NSLog(@"输出修改后的值和地址"); NSLog(@"str1 = %@, str1_p = %p", str1, str1); NSLog(@"str2 = %@, str2_p = %p", str2, str2); //调用block myBlock(); NSLog(@"******************************************"); NSLog(@"调用block后的值和地址"); NSLog(@"str1 = %@, str1_p = %p", str1, str1); NSLog(@"str2 = %@, str2_p = %p", str2, str2);} |
代码说明:给定义的各一个可变和不可变的对象一个初始值,然后在调用代码块的时候修改两个局部变量的值,然后再代码块中显示变量的值。
运行结果如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
2014-08-10 13:30:25.710 Memory[1074:303] 两个字符串的初始值和初始地址2014-08-10 13:30:25.711 Memory[1074:303] str1 = str1, str1_p = 0x100005ef02014-08-10 13:30:25.712 Memory[1074:303] str2 = str2, str2_p = 0x1002043302014-08-10 13:30:25.712 Memory[1074:303] ******************************************2014-08-10 13:30:25.712 Memory[1074:303] 输出修改后的值和地址2014-08-10 13:30:25.713 Memory[1074:303] str1 = str1_update, str1_p = 0x100005fd02014-08-10 13:30:25.713 Memory[1074:303] str2 = str2_update, str2_p = 0x1002043302014-08-10 13:30:25.713 Memory[1074:303] ******************************************2014-08-10 13:30:25.714 Memory[1074:303] 在block块中输出局部变量的可变和不可变变量2014-08-10 13:30:25.714 Memory[1074:303] str1 = str1, str1_p = 0x100005ef02014-08-10 13:30:25.714 Memory[1074:303] str2 = str2_update, str2_p = 0x1002043302014-08-10 13:30:25.714 Memory[1074:303] ******************************************2014-08-10 13:30:25.715 Memory[1074:303] 调用block后的值和地址2014-08-10 13:30:25.715 Memory[1074:303] str1 = str1_update, str1_p = 0x100005fd02014-08-10 13:30:25.715 Memory[1074:303] str2 = str2_update, str2_p = 0x100204330 |
从上面的输出结果我们可以看到,在代码块中输出的不可变对象是原有的值,而不是我们改后的值,地址也是初始的地址。而对于可变对象,值是我们修改后的值,而地址使用原有的地址。如果要想block和不可变局部变量绑定的话,我们要加上_block
还是引用上面博客中的一段话来做一下总结吧:
对值类型的修改,如果block初始化后,无法同步到block内部
对于引用类型的修改,如果block初始化后,修改指针指向,即指向另外一块内存,这样也是无法同步到block内部
对于引用类型的修改,如果block初始化后,对指针指向的内存进行修改,即NSMutableArray add 、remove操作,这样是可以用同步到block内部,但block内部同样无法修改。
2.成员变量在block中的使用
成员变量在block中的使用是加上self->a使用的,所以在声明成员变量的时候加不加__block,在成员函数中的代码块中都可以访问修改;
代码走起:
interface:
|
1
2
3
4
5
6
7
8
9
10
|
@interface BlockTest : NSObject//声明两个成员变量一个用__block 和 不用__block修饰观察其变化{ __block NSString *hasBlock; NSString *noBlock;}-(void)test;@end |
方法的实现:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
@implementation BlockTest-(void)test{ //分别给两个成员变量赋初始值 hasBlock = @"ludashi"; noBlock = @"ludashi"; NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock); NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock); //定义block void (^myBlock)() = ^() { //修改加__block的成员变量的值 hasBlock = @"ludashi_update"; NSLog(@"block中输出的内容"); NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock); NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock); }; //改变noBlock的值 noBlock = @"ludashi_update"; NSLog(@"更新后的值"); NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock); NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock); //调用block myBlock(); //调用block后的值 NSLog(@"调用myBlock后的值"); NSLog(@"hasBlock = %@, hasBlock_p = %p", hasBlock, hasBlock); NSLog(@" noBlock = %@, noBlock_p = %p", noBlock, noBlock);}@end |
输出结果:
|
1
2
3
4
5
6
7
8
9
10
11
|
2014-08-10 16:32:42.497 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x1000061882014-08-10 16:32:42.499 Memory[1349:303] noBlock = ludashi, noBlock_p = 0x1000061882014-08-10 16:32:42.499 Memory[1349:303] 更新后的值2014-08-10 16:32:42.500 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x1000061882014-08-10 16:32:42.500 Memory[1349:303] noBlock = ludashi_update, noBlock_p = 0x1000068282014-08-10 16:32:42.500 Memory[1349:303] block中输出的内容2014-08-10 16:32:42.501 Memory[1349:303] hasBlock = ludashi_update, hasBlock_p = 0x1000068282014-08-10 16:32:42.501 Memory[1349:303] noBlock = ludashi_update, noBlock_p = 0x1000068282014-08-10 16:32:42.501 Memory[1349:303] 调用myBlock后的值2014-08-10 16:32:42.502 Memory[1349:303] hasBlock = ludashi_update, hasBlock_p = 0x1000068282014-08-10 16:32:42.502 Memory[1349:303] noBlock = ludashi_update, noBlock_p = 0x100006828 |
总结:
对于一个、多个成员变量,不管是否用__block修饰(用不用都没任何影响),block结构体会生成一个成员 :self,并且会引用成员变量所属的对象实例 self。
对于成员变量的修改都是通过对象self指针引用来实现的。
block内部对于成员变量的访问也是通过block结构体对象的成员self 指针引用来实现的。
Objective-C中的Block(闭包)的更多相关文章
- Objective-C中的Block(闭包) (轉載)
来源: 伯乐在线 - 青玉伏案 链接:http://ios.jobbole.com/83229/ 学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西.学过 ...
- iOS开发之OC与swift开发混编教程,代理的相互调用,block的实现。OC调用Swift中的代理, OC调用Swift中的Block 闭包
本文章将从两个方向分别介绍 OC 与 swift 混编 1. 第一个方向从 swift工程 中引入 oc类 1. 1 如何在swift的类中使用oc类 1.2 如何在swift中实现oc的代理 ...
- Swift: 比较Swift中闭包传值、OC中的Block传值
一.介绍 开发者对匿名函数应该很清楚,其实它就是一个没有名字的函数或者方法,给人直观的感觉就是只能看到参数和返回值.在iOS开发中中,它又有自己的称呼,在OC中叫Block代码块,在Swift中叫闭包 ...
- Objective-C中的Block回调模式
在前面的博客中提到了Block的概念和使用方法,个人感觉Block最爽的用法莫过于在回调时用block.感觉比委托回调和目标方法回调用着要顺手,好不好用还得读者亲自用一下才知道.如果 读者之前用过SS ...
- ios 中的block应用
在这个大冬天里默默敲着键盘,勿喷.今天学习swift过程中,学习到闭包,发现闭包和oc的block中有很多的相同之处,又重新学习了一下并且学习了一些高级点的用法,内容如下: 1.block格式说明:( ...
- Objective-C中的Block
1.相关概念 在这篇笔记开始之前,我们需要对以下概念有所了解. 1.1 操作系统中的栈和堆 注:这里所说的堆和栈与数据结构中的堆和栈不是一回事. 我们先来看看一个由C/C++/OBJC编译的程序占用内 ...
- Swift 中的Closures(闭包)详解
Swift 中的Closures(闭包)详解 在Swift没有发布之前,所有人使用OC语言编写Cocoa上的程序,而其中经常被人们讨论的其中之一 -- Block 一直备受大家的喜爱.在Swift中, ...
- 浅析Block闭包
浅析Block闭包 简单来说,block就是将函数及其上下文封装起来的对象,从功能上可以把它看作是C++中的匿名函数,也可称之为块. Block类型写法: 返回值+(^块名)+(参数)= ^(参数){ ...
- iOS中为什么block用copy属性
1. Block的声明和线程安全Block属性的声明,首先需要用copy修饰符,因为只有copy后的Block才会在堆中,栈中的Block的生命周期是和栈绑定的,可以参考之前的文章(iOS: 非ARC ...
随机推荐
- Linux 环境变量 设置 etc profile
一.Linux的变量种类 按变量的生存周期来划分,Linux变量可分为两类: 1.永久的:需要修改配置文件,变量永久生效. 2.临时的:使用export命令声明即可,变量在关闭shell时失效. 二. ...
- div 添加滚动条
<div id="dic" style="overflow:auto">
- MLlib决策树与集成树
决策树是一种常见的分类与回归机器学习算法,由于其模型表达性好,便于理解,并能取得较好的效果,而受到广泛的应用.下图是一个简单的决策树,决策树每个非叶子节点包含一个条件,对于具有连续值的特征,该条件为一 ...
- Java中9种IO的读取方式
数据的读写,按照数据类型可以分为两种:字符流和字节流(二者区别?).所以数据读取方式按照数据类型也可以分为两类:字节流的读取和字符流的读取. 一.字节流读取操作: | | |-----1.FileI ...
- Python模块之day4
模块,代码归类实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才能 ...
- call和bind改变的上下文环境
这周自我学习的时间很宽裕.正巧一直对call和apply不甚理解(虽然bind还经常用到,仅仅是知道这么用有这个效果= =,而不知为何有这个效果),下午就自己写写demo,帮助自己理解. functi ...
- C#3.0扩展方法学习篇
什么是类的扩展方法 扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型. MSDN Extension methods enable you to &q ...
- io.js的服務器突破
Node.js与io.js那些事儿 InfoQ中文站 05月20日 14:26 去年12月,多位重量级Node.js开发者不满Joyent对Node.js的管理,自立门户创建了io.js.io.js的 ...
- 剑指Offer面试题:13.调整数组顺序使奇数位于偶数前面
一.题目:调整数组顺序使奇数位于偶数前面 题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 例如有以下一个整数数组:12345 ...
- Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(2)
Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(2) 上一篇里介绍了Color-Coded Picking的思路和最基本的实现.在处理GL_POINTS时已经没有问题,但是处 ...