Ø Block 封装了一段代码,可以在任何时候执行
Ø Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。
Ø 苹果官方建议尽量多用block。在多线程、异步任务、集合遍历、集合排序、动画转场用的很多
1.Block的定义
typedef
先声明类型,再定义变量进行赋值
Typedef
int (^MySum)(
int,
int) ;
Mysum sum = ^(
int a,
int b) {
return a+b; };
在声明的同时定义变量,然后赋值
int (^MySum)(
int,
int) = ^(
int a,
int b) {
return a+b; }; 定义了一个叫MySum的blocks对象,它带有两个 int参数,返回 int。等式右边就是blocks的具体实现 Block 可以访问局部变量,但是不能修改。 int sum = 10; int (^MyBlock)( int) = ^( int num) { sum++; // 编译报错 return num * sum;
};
如果要修改就要加关键字:
__block
__block
int sum =
10;
|
2.Block和函数指针对比
定义函数指针
int (*myFn)();
定义Block
int (^MyBlock)(
int,
int);
调用函数指针
(*myFn)(
10,
20);
调用Block
MyBlock(
10,
20);
|
3. 利用Block传值
1.要传值的一边定义block
//定义Block别名
typedef
void(^MyBlock)(
NSString *text);
//定义Block类型属性
@property(
nonatomic,
copy)
MyBlock block;
@property (
weak,
nonatomic)
IBOutlet UITextField *textFiekd;
//这时block的参数就是_textFiekd.text
if (
self.delegate respondsToSelector:
@selector(_block:)) {
_block(
_textFiekd.
text);
}
2.接收值的一边
//实现传值方定义的Block
- (
void)viewWillAppear:(
BOOL)animated {
[ super viewWillAppear:animated];
//实现block 里面的参数text就是上面的_textFiekd.text
secondCtrl.block = ^(NSString *text) {
_label.text = text;
};
}
-------------------------------------------实现多个block传值-
------------------------------------------
1.传值方定义block,提供一个实现block事件的方法
typedef
void(^fontColor)(
UIColor *color);
typedef void(^fontSize)( CGFloat size); typedef void(^more)(); @interface HeadView : UIView @property ( nonatomic, copy) fontColor color; @property ( nonatomic, copy) fontSize size; @property ( nonatomic, copy) more eraser; @property ( nonatomic, copy) more undo; @property ( nonatomic, copy) more clear; - ( void)blockWithColor:( fontColor)color andFontSize:( fontSize)size andEraser:( more)eraser andUndo:( more)undo
andClear:(
more)clear;
- (
void)blockWithColor:(
fontColor)color andFontSize:(
fontSize)size andEraser:(
more)eraser andUndo:(
more)undo andClear:(
more)clear
{ _color = color; _size = size; _eraser = eraser; _undo = undo; _clear = clear;
}
2.接收值方实现block(
注意:哪里有接收方的对象就放到哪里实现)
[headView
blockWithColor:^(
UIColor *color) {
drawView. drawColor = color; } andFontSize:^( CGFloat size) { drawView. fontSize = size; } andEraser:^{ [drawView eraser]; } andUndo:^{ [drawView undo]; } andClear:^{ [drawView clear];
}];
|
4.利用block改写Button点击事件
1.抽出一个继承于UIButton的类,自定义按钮
2.这个类中有一个block属性(参数为UIButton类型)和一个能实现添加事件功能的方法
3.在内部利用 addTarget 实现这个方法,实现点击事件时调用block
4.在其他地方创建这个类型对象就可以调用block,来实现模仿系统添加事件的功能
------------------------------------------------------------.h-----------------------------------------------------------
//定义block别名
typedef
void(^BlockBtn)(
UIButton *btn);
@property (
nonatomic,
copy)
BlockBtn btnBlock;
// 对外提供方法(这就是对外的 addTarget 方法)
- (
void)addBlockAction:(
BlockBtn)block;
------------------------------------------------------------.m-----------------------------------------------------------
- (
void)addBlockAction:(
BlockBtn)btnBlock
{
//内部调用
[
self
addTarget:
self
action:
@selector(blockAction)
forControlEvents:
UIControlEventTouchUpInside];
//将btnBlock值存放到全局变量
_btnBlock = btnBlock;
} - ( void)blockAction { if ( _btn != nil) { _btn( self); }
}
------------------------------------------------------------调用-----------------------------------------------------------
[btn
addBlockAction:^(
UIButton *btn) {
NSLog(
@"
实现了
");
}];
|
5.利用block改写UIAlertView代理
1.抽出一个继承于
UIAlertView
的类,重写init方法
2.这个类中有一个block属性(参数为
NSInteger
类型)
3.在内部实现init方法,实现初始化时将block变量保存到自己的block属性变量
4.在其他地方创建这个类型对象就可以实现block,不用
------------------------------------------------------------.h-----------------------------------------------------------
遵守协议
UIAlertViewDelegate
//1.
定义
block
别名
typedef
void (^MyBlock)(
NSInteger index);
@interface MyAlertView : UIAlertView //2. 定义 block 属性 @property( nonatomic, copy) MyBlock block; //3. 重写初始化方法 - ( id)initWithTitle:( NSString *)title message:( NSString *)message cancelButtonTitle:( NSString *)cancelButtonTitle otherButtonTitles:( NSString*)otherButtonTitles
block:(
MyBlock)block;
------------------------------------------------------------.m-----------------------------------------------------------
//
重写初始化方法
- ( id)initWithTitle:( NSString *)title message:( NSString *)message cancelButtonTitle:( NSString *)cancelButtonTitle otherButtonTitles:( NSString*)otherButtonTitles block:( MyBlock)block{ // 初始化父类初始化方法 if( self = [ super initWithTitle:title message:message delegate: self cancelButtonTitle:cancelButtonTitle otherButtonTitles:otherButtonTitles, nil]) { // 将变量存放到全局 _block = block; } return self; } // 在调用代理方法时实现 block - ( void)alertView:( UIAlertView *)alertView clickedButtonAtIndex:( NSInteger)index{ _block(index);
}
------------------------------------------------------------调用-----------------------------------------------------------
- (
IBAction)btn:(
UIButton *)sender {
MyAlertView *alet = [[ MyAlertView alloc] initWithTitle: @" 注意 " message: nil cancelButtonTitle: @" 取消 " otherButtonTitles: @" 确定 " block:^( NSInteger index) { if(index == 0){ NSLog( @" 点击了取消 "); } else if (index == 1) { NSLog( @" 点击了确定 "); } }]; [alet show];
}
|
6.MRC下的Block
//------------
在
block
中使用局部变量对内存的影响
------------
(
1
)在
block
内部使用局部变量(非对象)的时候,会将数据拷贝一份存放在常量区域,所以不能在
block
中更改数据,如果想更改,则需要使用
__block
__block
int a =
10;
(
2
)在
block
中使用局部对象
,block
会将对象计数值加一
//
如果想计数值不加以,使用
__block
//----------------------MRC----------------------------
如果在
block
中使用全局变量,他为了持有这个变量,会将对应的对象加一
//
使用
__block
,避免循环引用
//block -> self -> self.view -> button -> block
__block
SecondViewController *this =
self;
[button
addBlockAction:^(
UIButton *button) {
this-> _index = 20; // 会将 self 加一
[this.
navigationController
popViewControllerAnimated:
YES];
}]; |
7.ARC下的Block
//block -> self -> self.view -> button -> block
__block在ARC情况下,只能用于修饰局部变量 // 下面写法没有作用 __block SecondViewController *this = self; //1. 使用 __weak, 可以解决循环引用 , 但是不能访问当前类中属性 __weak SecondViewController *weakThis = self; // 按钮的点击事件 [button addBlockAction:^( UIButton *button) { //2. 如果想访问当前类的属性有两种方法: //(1) 如果不想吧属性公布出去,就再用 __strong 修饰一下 __strong SecondViewController *strongThis = weakThis; strongThis -> _index = 30; //(2) 如果属性可以对外公布 , 可以把属性写成 property weakThis. index = 30; // 调用对象方法 [weakThis test];
}];
|