iOS 三大回调方式:目标动作回调,委托回调,代码块回调,喜欢 block 是因为他很简洁紧凑,代码可读性高。
block 格式
block 简单操作
无返回值无参数
void(^block)(void) = ^{
NSLog(@"Hello, World!");
};
block(); // 调用方式
无返回值有参数
void(^block)(int) = ^(int value){
NSLog(@"小狗%d个月大了",value);
};
block(6);
Block[22835:1629584] 小狗6个月大了
无返回值多参数
void(^block)(NSString *,int) = ^(NSString *name, int number){
NSLog(@"%@已经%d个月大了",name,number);
};
block(@"猫猫",3);
Block[22902:1635602] 猫猫已经3个月大了
有返回值多参数
NSString *(^block)(NSString *,int) = ^(NSString *name, int number){
return [NSString stringWithFormat:@"%@已经%d个月大了",name,number];
};
NSLog(@"%@",block(@"猫猫",3));
Block[22933:1639591] 猫猫已经3个月大了
block 还有一个功能,捕获变量的能力。
int b = 6;
void(^add)(int) = ^(int a){
NSLog(@"%d",a + b);
};
add(10);
Block[23038:1657584] 16
但是在示例当中代码块里面只能获取,不能改变 b 的值,不然会报错。想要在代码块里面改变值,只需要在 声明变量前加一个前缀 __block ,就可以了。
__block int b = 6;
void(^add)(int) = ^(int a){
b = b + a;
};
add(10);
NSLog(@"b = %d",b);
Block[23165:1673618] b = 16
原因:在未加前缀之前,block 传递的是 b 的值,添加前缀后而是把 b 的地址传过去了,所以在block内部便可以修改到外面的变量了。
还可以用 typedef 声明 block。
#import <Foundation/Foundation.h>
typedef void(^Block)(NSString *text);
@interface Person : NSObject
@property (nonatomic, copy) Block block;
@property (nonatomic, copy) NSString *name;
- (void)callYouBack;
@end
#import "Person.h"
@implementation Person
- (void)callYouBack {
// 判断是否初始化了 block, 不然会奔溃
if (self.block) {
self.block(@"回电话");
}
}
- (void)dealloc {
NSLog(@"释放%@",self);
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc] init];
// 初始化 block
p.block = ^(NSString *text) {
NSLog(@"text = %@",text);
};
[p callYouBack];
}
return 0;
}
Block[23476:1713267] text = 回电话
Block[23606:1724744] 释放<Person: 0x10043c1e0>
有个需求需要在代码块里面,给 p 类中的 name 赋值。
Person *p = [[Person alloc] init];
// 初始化 block
p.block = ^(NSString *text) {
NSLog(@"text = %@",text);
p.name = @"张三";
};
[p callYouBack];
Block[23476:1713267] text = 回电话
程序执行完,发现一个问题! p 类没有释放掉内存。
这里面是因为循环引用了,p 持有了 block,而 block 又持有了 p。所以才释放不了。
解决方式: weak 弱引用
Person *p = [[Person alloc] init];
// 创建 block
__weak typeof(p) weakP = p;
p.block = ^(NSString *text) {
NSLog(@"text = %@",text);
weakP.name = @"张三";
};
[p callYouBack];
Block[23606:1724744] text = 回电话
Block[23606:1724744] 释放<Person: 0x10043c1e0>