基本原理
- Block 也是OC的对象
- Objective-C 是对C 语言的扩展,block的实现是基于指针和函数指针
- 代码输入 inlineBlock 就会出再一段block代码,类似于init
block 内存分类
内存分布
堆区 栈区 全局区 代码区
1.没捕获有外部变量 GlobalBlock 全局区
2.有捕获外部变量:
A. 全部变量 或 全局静态变量 或 局部静态变量
copy 或 strong 或weak 修饰 GlobalBlock
B. 普通外部变量:
copy 或 strong 修饰 mallocBlock
weak 修饰 stackBlock 意为着出了方法或函数范围就失效了
分析:
有普通外部变量时:创建Block时本身在栈区,但赋值时用Stong或Copy时会将block 从栈区移到堆区
block 的创建
void(^blockName)(NSString *) = ^(NSString *param) {
NSLog(@"%@",param);
};
blockName(@"hello");
#声明 返回值类型(^block名称)(参数列表)
void(^Block1)( );
#实现 block = ^(参数列表){ 代码块 }
Block1 = ^( ){
NSLog(@"我的代码块");
}
#调用 block名称(参数列表)
Block( );
block 作属性参数使用
@property (nonatomic, copy) void(^blockName)(NSString *);
//一般用 tyedef
tyedef NSString(^Block2 )(NSString *, NSString *)
block 做方法参数使用
void(^Block2)(int,int) = ^(int a, int b){
NSLog(@"我的第二个代码块");
}
[self method:block2];
-(void)method:(void(^)(int,int))block{
block(10,20)
}
Tips
- (void)viewDidLoad
{
[super viewDidLoad];
int a = 3;
void (^ block)() = ^{
NSLog(@"%d",a);
};
a = 5;
block();
}
————————————————————————————————————
情况2:
- (void)viewDidLoad
{
[super viewDidLoad];
static int a = 3; ***区别点:静态变量***
void (^ block)() = ^{
NSLog(@"%d",a);
};
a = 5;
block();
}
————————————————————————————————————
情况3:
- (void)viewDidLoad
{
[super viewDidLoad];
__block int a = 3; ***区别点:被__block修饰***
void (^ block)() = ^{
NSLog(@"%d",a);
};
a = 5;
block();
}
————————————————————————————————————
情况4:
__block int a = 3; ***区别点:全局变量***
- (void)viewDidLoad
{
[super viewDidLoad];
void (^ block)() = ^{
NSLog(@"%d",a);
};
a = 5;
block();
}
//局部变量,block传值(值拷贝);
//静态变量,全局变量,__block修饰,blokc传址(址拷贝);
循环引用
一般我们为避免block中相互持有而造成谁都无法释放,引起循环引用,从而造成内存泄露,所以需要typeof(self)[1]
__weak typeof(self) weakSelf = self; //推荐写法
__weak __typeof(self) weakSelf = self;
__weak XXViewController *weakSelf = self;
__weak id weakSelf = self;
__weak __typeof(&*self)weakSelf = self;
//当然也可以写成宏定义
#define WF(weakSelf) __weak typeof(self) weakSelf = self;
NSString str = @"测试1";
typeof(a) b = @"测试2";
typeof(a) 表示得到对象a的类型
但有些情况可以直接使用self
- 调用系统方法:
//block虽然对self 强引用,但self不持有这个静态方法
[UIView animateWithDuration:0.5 animations:^{
NSLog(@"%@",self);
}];
- block 不是self 的属性
//self不持有这个block,所以也不存在循环引用
void(^block)(void) = ^(){
NSLog("%@",self);
}
Block 与 Delegate
两者非常类似,用法也相近,比如我们自定义一个UITableViewCell,cell上显示文字信息和一个请情Button,点击button后push到下一个页面。但cell 没有能力实现 push 功能,因为只能是
[self.navigationController pushViewController:VC];
- 如果用代理的话,Cell 需要制定协议,设置代理,委托代理实现 push 功能
//设置协议
@protocol CustomCellDelegate
- (void)pushToNewPage;
@end
@interface CustomTableViewCell : UITableViewCell
@property(nonatomic, assign) id delegate;
@property (nonatomic, strong) UILabel *text1Label;
@property(nonatomic,strong) UIButton *detailBtn;
@end
//在cell的.m文件中给Button添加方法
[self.detailBtn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
//对应的btnClicked方法
- (void)btnClicked:(UIButton *)btn{
//最好做这种安全判断
if (self.delegate && [self.delegaterespondsToSelector:@selector(pushToNewPage)]) {
[self.delegate pushToNewPage];
}
}
//在ViewController的.m文件中遵守协议
@interface ViewController ()
@end
//设置代理
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
····
//很重要
cell.delegate = self;
return cell;
}
//实现协议方法
- (void)pushToNewPage{
DetailViewController*detailVC = [[DetailViewController alloc] init];
[self.navigationController pushViewController:detailVC animated:YES];
}
- 如果用Block的,不需要制定协议
@interface CustomTableViewCell : UITableViewCell
//直接定义一个block
@property (nonatomic, copy) void (^ButtonBlock)();
@property (nonatomic, strong) UILabel *text1Label;
@property(nonatomic,strong) UIButton *detailBtn;
@end
//在cell的.m文件中给Button添加方法
[self.detailBtn addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
//对应的btnClicked方法
-(void)btnClicked:(UIButton *)btn{
//最好做这种安全判断
if (ButtonBlock) {
ButtonBlock( )
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
····
//很重要
cell.ButtonBlock = ^{
[self pushToNewPage];
}
参考文档
-
typeof(a) 和 __typeof(a) 都可以,但 可能是苹果比较推荐前者 ↩