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) (intint);

无返回值的


1

void (^myBlock)(intint);

2.给block块赋值

给声明好的block,赋值。block的值就是个函数体,给block块赋值有两种方式,一个在声明的时候赋值,一个是先声明在赋值。

先声明再赋值


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

//代码块的声明

void (^myBlock)(intint);

//给代码块赋值

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) (intint) = ^(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)(intint))

{

    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 = 0x100005ef0

2014-08-10 13:30:25.712 Memory[1074:303] str2 = str2,  str2_p = 0x100204330

2014-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 = 0x100005fd0

2014-08-10 13:30:25.713 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330

2014-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 = 0x100005ef0

2014-08-10 13:30:25.714 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330

2014-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 = 0x100005fd0

2014-08-10 13:30:25.715 Memory[1074:303] str2 = str2_update,  str2_p = 0x100204330

从上面的输出结果我们可以看到,在代码块中输出的不可变对象是原有的值,而不是我们改后的值,地址也是初始的地址。而对于可变对象,值是我们修改后的值,而地址使用原有的地址。如果要想block和不可变局部变量绑定的话,我们要加上_block

还是引用上面博客中的一段话来做一下总结吧:

  1. 对值类型的修改,如果block初始化后,无法同步到block内部

  2. 对于引用类型的修改,如果block初始化后,修改指针指向,即指向另外一块内存,这样也是无法同步到block内部

  3. 对于引用类型的修改,如果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 = 0x100006188

2014-08-10 16:32:42.499 Memory[1349:303]  noBlock = ludashi,  noBlock_p = 0x100006188

2014-08-10 16:32:42.499 Memory[1349:303] 更新后的值

2014-08-10 16:32:42.500 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x100006188

2014-08-10 16:32:42.500 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828

2014-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 = 0x100006828

2014-08-10 16:32:42.501 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828

2014-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 = 0x100006828

2014-08-10 16:32:42.502 Memory[1349:303]  noBlock = ludashi_update,  noBlock_p = 0x100006828

总结:

  1. 对于一个、多个成员变量,不管是否用__block修饰(用不用都没任何影响),block结构体会生成一个成员 :self,并且会引用成员变量所属的对象实例 self。

  2. 对于成员变量的修改都是通过对象self指针引用来实现的。

  3. block内部对于成员变量的访问也是通过block结构体对象的成员self 指针引用来实现的。

Objective-C中的Block(闭包)

时间: 2024-11-02 14:33:58

Objective-C中的Block(闭包)的相关文章

block使用小结、在arc中使用block、如何防止循环引用

引言 使用block已经有一段时间了,感觉自己了解的还行,但是几天前看到CocoaChina上一个关于block的小测试主题 : [小测试]你真的知道blocks在Objective-C中是怎么工作的吗?,发现竟然做错了几道, 才知道自己想当然的理解是错误的,所以抽时间学习了下,并且通过一些测试代码进行测试,产生这篇博客. Block简介(copy一段) Block作为C语言的扩展,并不是高新技术,和其他语言的闭包或lambda表达式是一回事.需要注意的是由于Objective-C在iOS中不支

Objective-c中的Block(块)详解

Block初探 在Objective-c中NSArray是很常用的容器之一,很多时候我们需要对数组中的数据进行排序,因此与下面类似的代码会经常碰到: NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) { if ([obj1 integerValue] > [obj2 integerValue]) { return (NSComparisonResult)NSOrderedDescending

从C语言的变量声明到Objective-C中的Block语法转载]

原文:From C Declarators to Objective-C Blocks Syntax 作者:Nils Hayat 译者:CocoaChina--sunshine 在这篇文章中,从简单的C语言中各种声明开始,以及复杂的声明组合,到最后Objective-C中的代码块bokck的语法. 花一些时间去了解代码块(block)衍生和组织形式,一旦明白了这些,就可以很方便的声明和使用它,而不用每次需要的时候才去Google一下. 如果你想把能想到的东西用block声明表现出来,请继续阅读!

ios 中的block应用

在这个大冬天里默默敲着键盘,勿喷.今天学习swift过程中,学习到闭包,发现闭包和oc的block中有很多的相同之处,又重新学习了一下并且学习了一些高级点的用法,内容如下: 1.block格式说明:(返回类型)(^块名称)(参数类型) = ^(参数列表) {代码实现};//如果没有参数,等号后面参数列表的()可以省略 例子: void(^demoBlock)() = ^ { NSLog(@"demo Block"); }; int(^sumBlock)(int, int) = ^(in

Objective-C中的Block

1.相关概念 在这篇笔记开始之前,我们需要对以下概念有所了解. 1.1 操作系统中的栈和堆 注:这里所说的堆和栈与数据结构中的堆和栈不是一回事. 我们先来看看一个由C/C++/OBJC编译的程序占用内存分布的结构: 栈区(stack):由系统自动分配,一般存放函数参数值.局部变量的值等.由编译器自动创建与释放.其操作方式类似于数据结构中的栈,即后进先出.先进后出的原则. 例如:在函数中申明一个局部变量int b;系统自动在栈中为b开辟空间. 堆区(heap):一般由程序员申请并指明大小,最终也由

Objective-C中的Block[转]

1.相关概念 在这篇笔记开始之前,我们需要对以下概念有所了解. 1.1 操作系统中的栈和堆 注:这里所说的堆和栈与数据结构中的堆和栈不是一回事. 我们先来看看一个由C/C++/OBJC编译的程序占用内存分布的结构: 栈区(stack):由系统自动分配,一般存放函数参数值.局部变量的值等.由编译器自动创建与释放.其操作方式类似于数据结构中的栈,即后进先出.先进后出的原则. 例如:在函数中申明一个局部变量int b;系统自动在栈中为b开辟空间. 堆区(heap):一般由程序员申请并指明大小,最终也由

Swift 中的Closures(闭包)详解

Swift 中的Closures(闭包)详解 在Swift没有发布之前,所有人使用OC语言编写Cocoa上的程序,而其中经常被人们讨论的其中之一 -- Block 一直备受大家的喜爱.在Swift中,同样有这样的一个角色,用于当开发者需要异步执行的之后使用的一种语法 - Closure.中文翻译为闭包. 闭包出了可以进行异步执行之外,它的完整使用还依赖闭包本身的变量.常量的捕获.闭包捕获并存储对它们定义的上下文中的任何常量和变量的引用,这也就意味着,你可以在任何时候异步执行闭包的时候获取之前的所

如何在iOS中使用Block

如何在iOS中使用Block Block可以帮助我们组织独立的代码段,并提高复用性和可读性.iOS4在UIKit中引入了该特征.超过100个的Apple API都使用了Block,所以这是一个我们必须开始熟悉的知识. Block是什么样的? 你可以使用^操作符来声明一个Block变量,它表示一个Block的开始. int num1 = 7; int(^aBlock)(int) = ^)int num2) { return num1+nunm2; }; 在如上代码中我们将Block声明为一个变量,

malloc中 heap block 的 blocksize 大小问题

heap block 引发的思考 问题背景: Implicit Free Lists Any practical allocator needs some data structure that allows it to distinguish block boundaries and to distinguish between allocated and free blocks. Most allocators embed this information in the blocks the