Objective-C中的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
|
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
还是引用上面博客中的一段话来做一下总结吧:
-
对值类型的修改,如果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 = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> hasBlock_p = %p"
,
hasBlock
,
hasBlock
)
;
NSLog
(
@" noBlock = %@, noBlock_p = %p"
,
noBlock
,
noBlock
)
;
//定义block
void
(
^
myBlock
)
(
)
=
^
(
)
{
//修改加__block的成员变量的值
hasBlock
=
@"ludashi_update"
;
NSLog
(
@"block中输出的内容"
)
;
NSLog
(
@"hasBlock = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> hasBlock_p = %p"
,
hasBlock
,
hasBlock
)
;
NSLog
(
@" noBlock = %@, noBlock_p = %p"
,
noBlock
,
noBlock
)
;
}
;
//改变noBlock的值
noBlock
=
@"ludashi_update"
;
NSLog
(
@"更新后的值"
)
;
NSLog
(
@"hasBlock = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> hasBlock_p = %p"
,
hasBlock
,
hasBlock
)
;
NSLog
(
@" noBlock = %@, noBlock_p = %p"
,
noBlock
,
noBlock
)
;
//调用block
myBlock
(
)
;
//调用block后的值
NSLog
(
@"调用myBlock后的值"
)
;
NSLog
(
@"hasBlock = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> 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
|
总结:
-
对于一个、多个成员变量,不管是否用__block修饰(用不用都没任何影响),block结构体会生成一个成员 :self,并且会引用成员变量所属的对象实例 self。
-
对于成员变量的修改都是通过对象self指针引用来实现的。
-
block内部对于成员变量的访问也是通过block结构体对象的成员self 指针引用来实现的