1、Block的应用场景
对象与对象之间的通信方式。
2、 Block用法及和Delegate的区别:
Block:只有一个闭包,只能实现单一功能, 用Block能做到的大部分情况下代理都可以实现
Delegate:一个代理对象可以签署多个方法
(通知的通信方式是1对多;代理、Blocks是1对1。三种通信方式都实现了对象之间的解耦合)
3、Block的介绍
Block是IOS4.0之后新增的一种语法结构,也成为【闭包(closure)】;
SDK4.0新增的API大量使用了Block;
4、Block的使用
(1)声明(2)实现(3)调用
4.1、Block定义
//1.定义block
//int (*p)(int, int);
//caret,插入符
//返回值 (^block变量的名字)(参数列表)
int (^block)(int, float);
void (^block2)(int);
//2.block赋值
//block = ^返回值 (参数列表 形参的名字){
//
};
block = ^(int age, float height){
NSLog(@"block执行了");
return 0;
};
block2 = ^void (int a){
};
//1.定义和2.赋值合并
void (^block3)(int) = ^(int age){
NSLog(@"age");
};
//3.block调用
//回调
int result = block(23, 1.80);
NSLog(@"result = %d", result);
4.2、通过typedef声明block类型
//typedef给一个已有的变量类型定义一个别名
//typedef <#returnType#>(^<#name#>)(<#arguments#>);
//typedef 返回值 (^block的类型别名)(参数列表)
typedef int (^MyBlock)(int, float);
//typedef int MyInt;
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
int (^block1)(int age, float weight);
//block1
//int (^)(int, float)
//定义(声明)block
MyBlock block2;
block2 = ^(int age, float height){
return 0;
};
block2(20, 1.7);
[UIView animateWithDuration:1 animations:^{
;
}];
}
4.3、block作为参数传递
#import "ViewController.h"
typedef void(^MyBlock)(int, NSString *);
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//block赋值,作为参数传递给testBlock:
[self testBlock:^(int age, NSString *name){
NSLog(@"age = %d, name = %@", age, name);
}];
}
//block作为参数传递给testBlock方法
- (void)testBlock:(MyBlock)block
{
block(20, @"张三");
}
@end
5. block和变量及内存管理
变量按作用域分为全局变量和局部变量
5.1引用局部变量时,该变量会作为常量编码到Block块中;局部变量需要使用__block修饰,才能在Block块中修改
typedef void(^MyBlock)();
int num = 10;
MyBlock block = ^{
NSLog(@"%d",num);
};
num = 20;
block();
输出结果为10;
//添加__block修饰符,才可以修改
__block int num = 10;
MyBlock block = ^{
NSLog(@"%d",num);
};
num = 20;
block();
输出结果为20;
Block调用局部基本数据类型对象,进入到Block里面,num会变成变量,如果添加了关键字__block,那么在Block里面num就是同一个变量,我们就可以修改(也可以替换成static关键字):
__block int num = 10;
换成:static int num = 10;
5.2block引用局部对象,会retain该对象
NSObject *obj1 = [[NSObject alloc] init];
__block NSObject *obj2 = [[NSObject alloc] init];
MyBlock block = ^(int a){
NSLog(@"1----%@", obj1.retainCount); //obj1 retain 计数为2
NSLog(@"2----%@", obj2.retainCount); //obj2 计数为1
};
block(20);
[obj1 release];
[obj2 release];
5.3、block里引用全局变量
NSLog(@"%ld", self.retainCount);//2
MyBlock block = ^(int a){
//block里引用全局变量,会把全局变量所在的对象retain
num = 20;
NSLog(@"%ld", self.retainCount);//3
};
Block本身可以像对象一样copy和release,Block创建后内存分在栈上,调用copy方法,会将Block从栈移到堆上。当Block声明为全局变量时,我们应该调用Block的copy方法。
//注意此处是copy
@property(nonatomic, copy)NewBlock fBlock;
在Block(点语法)里面引用一个实例变量时,该实例对象会被retain,容易导致循环引用,循环用用会导致内存泄露。
6.Block的应用
将UIAlertView的按钮点击代理方法改为Block形式:
// ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController<UIAlertViewDelegate>
- (IBAction)buttonAction:(id)sender;
@end
----------
// ViewController.m
#import "ViewController.h"
#import "BlockView.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)buttonAction:(id)sender {
BlockView *blockView = [[BlockView alloc] initWithTitle:@"title" message:@"message" cancelButtonTitle:@"cancel" otherButtonTitles:@"OK" clickBlock:^(UIAlertView *alertView, NSInteger buttonIndex) {
if (buttonIndex == 0) {
NSLog(@"cancel");
}else {
NSLog(@"OK");
}
}];
[blockView show];
}
----------
// BlockView.h
#import <UIKit/UIKit.h>
typedef void(^TouchBlock)(UIAlertView *alertView,NSInteger buttonIndex);
@interface BlockView : UIAlertView
@property(nonatomic, copy)TouchBlock block;
- (id)initWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles
clickBlock:(TouchBlock)block;
@end
----------
// BlockView.m
#import "BlockView.h"
@implementation BlockView
- (id)initWithTitle:(NSString *)title
message:(NSString *)message
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles
clickBlock:(TouchBlock)block {
self = [super initWithTitle:title
message:message
delegate:self
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:otherButtonTitles, nil];
if (self) {
self.block = block;
}
return self;
}
//点击按钮后执行的协议方法
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (self.block) {
self.block(self, buttonIndex);
}
}
@end