博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Objective-C中的Block(闭包)
阅读量:5079 次
发布时间:2019-06-12

本文共 6571 字,大约阅读时间需要 21 分钟。

        学习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进阶 参考博客:/

        下面的这些内容是参考上面的博客进一步学习的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 指针引用来实现的。

转载于:https://www.cnblogs.com/ludashi/p/3903054.html

你可能感兴趣的文章
页面中公用的全选按钮,单选按钮组件的编写
查看>>
java笔记--用ThreadLocal管理线程,Callable<V>接口实现有返回值的线程
查看>>
BZOJ 1047 HAOI2007 理想的正方形 单调队列
查看>>
各种语言推断是否是手机设备
查看>>
这个看起来有点简单!--------实验吧
查看>>
PHP count down
查看>>
JVM参数调优:Eclipse启动实践
查看>>
(旧笔记搬家)struts.xml中单独页面跳转的配置
查看>>
不定期周末福利:数据结构与算法学习书单
查看>>
strlen函数
查看>>
python的列表与shell的数组
查看>>
关于TFS2010使用常见问题
查看>>
软件工程团队作业3
查看>>
python标准库——queue模块 的queue类(单向队列)
查看>>
火狐、谷歌、IE关于document.body.scrollTop和document.documentElement.scrollTop 以及值为0的问题...
查看>>
深入理解JVM读书笔记--字节码执行引擎
查看>>
vue-搜索功能-实时监听搜索框的输入,N毫秒请求一次数据
查看>>
批处理 windows 服务的安装与卸载
查看>>
React文档翻译 (快速入门)
查看>>
nodejs fs路径
查看>>