Block的学习随笔

1.Block的概念及基本用法
Block的实际行为和Function很像,最大的差别是在可以存取同一个Scope的变量值。Block实体形式如下:
^(传入参数列){行为主体};
Block实体开头是“^”,接着是由小括号所包起来的参数列(比如 int a, int b, int c),行为主体由大括号包起来,专有名字叫做block literal。行为主体可以用return回传值,类型会被compiler自动辨别。如果没有参数列要写成: ^(void)。
例子:
^(int a){return a*a;};

例子分析:
这是代表Block会回传输入值的平方值(int a 就是参数列, return a*a; 就是行为主体)。 记得行为主体里最后要加“;”,因为是叙述,而整个{}最后也要加“;”,因为Block是物件实体。用法如下:
[cpp] view plain copy
int result = ^(int a){return a*a;}(5);
NSLog(@"%d", result);
很奇怪吧?后面的小括号里面的5会被当成a的输入值,然后经由Block输出 5*5 = 25指定给result这个变量。
有没有简单一点的方法嗯?不然每次都写这么长?有。接下来介绍一个叫做Block Pointer的东西来简化我们的写法。
Block Pointer是这样定义的:

回传值(^名字)(参数列);

比如下面的例子:
[cpp] view plain copy
//声明一个square的Block Pointer,其所指向的Block有一个int输入和int输出
int (^square)(int);
//将Block实体指定给square
square = ^(int a){ return a*a ; };
//调用方法,感觉是是不是很像function的用法?
int result = square(5);
NSLog(@"%d", result);

把Block Pointer当成参数传递给一个function,比如
void myFunction(int (^mySquare)(int)); //function的定义,将Block作为参数
int (^mySquare)(int) = ^(int a){return a*a;}; //定义一个mySquare的Block pointer变量
myFunction(mySquare); //把mySquare作为myFunction的参数

//上三行代码代价于:
myFunction( ^int(int a){return a*a;} );

存取变量
1、可以读取和Block pointer同一个Scope的变量值:

[cpp] view plain copy
{
int outA = 8;
int (^myPtr)(int) = ^(int a){ return outA + a;};
//block里面可以读取同一类型的outA的值
int result = myPtr(3); // result is 11
NSLog(@"result=%d", result);
}

下面来看一段很有意思的代码:

[cpp] view plain copy
{
int outA = 8;
int (^myPtr)(int) = ^(int a){ return outA + a;}; //block里面可以读取同一类型的outA的值
outA = 5; //在调用myPtr之前改变outA的值
int result = myPtr(3); // result的值仍然是11,并不是8
NSLog(@"result=%d", result);
}

为什么result 的值仍然是11?而不是8呢?事实上,myPtr在其主体中用到的outA这个变量值的时候做了一个copy的动作,把outA的值copy下来。所以,之后outA即使换成了新的值,对于myPtr里面copy的值是没有影响的。
需要注意的是,这里copy的值是变量的值,如果它是一个记忆体的位置(地址),换句话说,就是这个变量是个指针的话,

它的值是可以在block里被改变的。如下例子:


[cpp] view plain copy
{
NSMutableArray *mutableArray = [NSMutableArray arrayWithObjects:@"one", @"two", @"three", nil];
int result = ^(int a){[mutableArray removeLastObject]; return a*a;}(5);
NSLog(@"test array :%@", mutableArray);
}

原本mutableArray的值是{@"one",@"two",@"three"},在block里面被更改mutableArray后,就变成{@"one", @"two"}了。
2、直接存取static类型的变量


[cpp] view plain copy
{
static int outA = 8;
int (^myPtr)(int) = ^(int a){return outA + a;};
outA = 5;
int result = myPtr(3); //result的值是8,因为outA是static类型的变量
NSLog(@"result=%d", result);
}
甚至可以直接在block里面修改outA的值,例如下面的写法:

[cpp] view plain copy
{
static int outA = 8;
int (^myPtr)(int) = ^(int a){ outA = 5; return outA + a;};
int result = myPtr(3); //result的值是8,因为outA是static类型的变量
NSLog(@"result=%d", result);
}

3、Block Variable类型的变量
在某个变量前面如果加上修饰字“__block”的话(注意,block前面有两个下划线),这个变量就称作block variable。

那么在block里面就可以任意修改此变量的值,如下代码:

[cpp] view plain copy
{
__block int num = 5;
int (^myPtr)(int) = ^(int a){return num++;};
int (^myPtr2)(int) = ^(int a){return num++;};
int result = myPtr(0); //result的值为5,num的值为6
result = myPtr2(0); //result的值为6,num的值为7
NSLog(@"result=%d", result);
}

2.block传值的使用步骤:
1>.有两个控制器,主动传值或者提供方法的控制器A,接受值的控制器B
2>.让A控制器typedef void(^myBlock)(),然后copy一个myBlock类型的属性:
@property(nonatomic ,copy) myBlock block;
3>.在B控制器中创建A控制器,然后调用A控制器的方法
4>.在A控制器方法中,记录block:self.block = block;
5>.在合适的地方调用block:self.block(poiResultList.poiInfoList);
6>.调用以后block参数里边已经有值,这个时候在B控制器中调用A控制器的方法中参数block开始执行,并且block中参数也已经有值.

3.block的传值原理:
1> 谁要传值,谁声明和定义block以及把block作为参数的方法
2>. 传值方记录下来block,在合适的时候调用
3> .接受值方,调用方法,等传值方调用block的时候才会在代码块中拿到block传过来的参数值.

4.Block需要注意的地方:
1,block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝。
2,非内联(inline) block 不能直接访问 self,只能通过将 self 当作参数传递到 block 中才能使用,并且此时的 self 只能通过 setter 或 getter 方法访问其属性,不能使用句点式方法。但内联 block 不受此限制。
3.使用 weak–strong dance 技术来避免循环引用.
在第二条中,我提到内联 block 可以直接引用 self,但是要非常小心地在 block 中引用 self。因为在一些内联 block 引用 self,可能会导致循环引用。

4,block 内存管理分析
block 其实也是一个 NSObject 对象,并且在大多数情况下,block 是分配在栈上面的,只有当 block 被定义为全局变量或 block 块中没有引用任何 automatic 变量时,block 才分配在全局数据段上。 __block 变量也是分配在栈上面的。

在 ARC 下,编译器会自动检测为我们处理了 block 的大部分内存管理,但当将 block 当作方法参数时候,编译器不会自动检测,需要我们手动拷贝该 block 对象。幸运的是,Cocoa 库中的大部分名称中包含”usingBlock“的接口以及 GCD 接口在其接口内部已经进行了拷贝操作,不需要我们再手动处理了。但除此之外的情况,就需要我们手动干预了。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值