要理解block和闭包需要和变量进行比较
首先在C中定义一个变量a:int a = 10;
定义一个block:
// 定义一个sumBlock
int(^sumBlock)(int, int) = ^(int a, int b) {
return a+b;
};
int c = sumBLock(1,2);// 使用block代码
定义一个闭包
let sum:(Int, Int) -> Int = { (a, b) -> Int in
return a + b
}
print(sum(1,2))
从上面的定义可以看出:
block可以归纳为:
// 定义一个sumBlock
返回值类型(^block名字)(形参列表) = ^(实参列表) {
表达式
return 返回数据;
};
返回类型 接收数据的变量名 = block名(实参列表);// 使用block代码
闭包的一般表达式
let 闭包名:(形参列表) -> 返回值类型 = { (实参列表) -> 返回值类型 in
表达式
return 返回值
}
print(包名(实参列表)) // 使用闭包
Blcok相关语法
BLock类型变量在BLock语法下,一旦使用了BLock就相当于生成了可复制给BLock类型变量的值,Block既指源码中给你的BLock语法也指有BLock生成的值
typedef int(^blk)(int); // 此时blk是一个BLock数据类型
blk bk = ^(int count){
return count + 1;
};
int (^blk1)(int) = bk;
int(^blk2)(int);
blk2 = blk1;
block会截获局部变量
int a = 10;
void(^logBlock)(void) = ^(void) {
NSLog(@"a=%d",a);
};
a = 20;
logBlock();
// 输出的是a=10
如果想在block中修改自动变量的值:
int val = 0;
void(^blk)(void) = ^{
val = 1;
};
blk();
printf("val = %d\n",val);
//会报错
}
如果想在block中修改外部变量需要在自动变量加上__block修饰词
__block iint val = 0;
void(^blk)(void) = ^{
val = 1;
};
blk();
printf("val is %d",val);
// 执行结果是 val is 1
在以下代码是不会报错:
NSMutableArray *arrayM = [NSMutableArray array];
void(^blk)(void) = ^(void) {
id obj = [[NSObject alloc] init];
[arrayM addObject:obj];
};
blk();
如果外部变量没有使用__block修饰,对该变量进行赋值就会报错,但是对数组进行添加是没有对数组进行赋值,是不会报错。
block作为参数的时候:
- (void)modelWithBLock:(void(^)(int, int))plus number:(int)a title:(NSString* )title
{
}
// 定义一个变量和一个block
//int a;
// void(^plus)(int, int);
// NSString *title;
在使用的时候直接使用括号包装起来,把变量名放到括号外面就好了
//(int)a
// (void(^)(int, int))plus
// (NSString*)title
闭包相关语法
利用typealias为闭包类型定义别名
typealias类似OC语法中的typedef
用法很简单,直接用 = 赋值就行了.
// 定义一个没有参数也没有返回值的别名
typealias Nothing = () -> ()
// 如果没有返回值也可以这样写
typealias Anything = () -> Void
// 接收一个参数没有返回值
typealias PringtNumber = (Int) -> ()
// 有参数,有返回值的
typealias Add = (Int, Int) -> (Int)
typealias Add = (_ num1: Int, _ num2: Int) -> (Int)
// 创建一个Add类型的闭包常量addCloser1
let addCloser1:Add
// 为已经创建好的常量进行赋值
addCloser1 = {
(_ num1:Int, _ num2: Int) -> Int in
return num1 + num2
}
// 调用闭包并接收返回值
let result = addCloser1(1,2)
2.闭包类型申明和变量的穿件合并在一起
let Add:(_ num1: Int, _ num2: Int) -> (Int)
Add = {
(_ num: Int, _ num2: Int) -> (Int) in
return num + num2
}
// 调用闭包并接收返回值
let result = Add(2,3)
3.省略闭包接收的形参、省略闭包体中返回值
let Add:(Int,Int) -> (Int)
Add = {
(num,num2) -> (Int) in
return num + num2
}
// 调用闭包并接收返回值
let result = Add(2,3)
4.在3的基础上继续精简
let Add:(Int, Int) -> (Int)
Add =
{ (num, num2) in
return num + num2
}
// 调用闭包并接收返回值
let result = Add(2,3)
5.如果闭包没有参数可以省略in
// 创建一个 () -> (String)类型的闭包常量:addCloser1并赋值
let addCloser1:() -> (String) = {
return "这个闭包没有参数,但是有返回值"
}
// 调用闭包并接收返回值
let result = addCloser1()
6.简写的实际参数名
// 创建一个(String,String) -> (String) 类型的闭包常量:addCloser1并赋值
let addCloser1:(String, String) -> (String) = {
return "闭包的返回值是:\($0),\($1)"
}
// 调用闭包并接受返回值
let result = addCloser1("Hello", "Swift")
$0和$1分别表示闭包的第一个和第二个String类型的实际参数
闭包作为函数的参数
1.尾随闭包
//函数的定义
func combie2(times: Int, handle:(String, String) -> (Void)) -> Void {
for i in 1...times {
handle("\(i)", "456")
}
}
// 函数的调用
combie2(times: 3) { (str1, str2) -> (Void) in
print("\(str1),\(str2)")
}
如果函数只有唯一的闭包参数,没有其他的参数可以省略函数的小括号
func combie2(handle:(String, String) -> (Void)) -> Void {
handle("123", "456")
}
combie2 { (str1, str2) -> (Void) in
print("\(str1), \(str2)")
}
2.逃逸闭包
后续补充。。。
在Swift中使用闭包不当可能引起循环强引用
class MainVC: UITabBarController {
var callBack:((String)->())?
override func viewDidLoad() {
super.viewDidLoad()
PringtString { (text) in
print(text)
// 闭包中捕获self
self.view.backgroundColor = UIColor.red
}
}
func PringtString(callBack:@escaping(String) -> ()) {
callBack("这个闭包返回一段文字")
// 控制器self强引用着callBack
self.callBack = callBack;
}
解决办法1、
class MainVC: UITabBarController {
var callBack:((String)->())?
override func viewDidLoad() {
super.viewDidLoad()
weak var weakSelf = self
PringtString { (text) in
print(text)
// 闭包中捕获self
weakSelf?.view.backgroundColor = UIColor.red
}
}
func PringtString(callBack:@escaping(String) -> ()) {
callBack("这个闭包返回一段文字")
// 控制器self强引用着callBack
self.callBack = callBack;
}
可以使用weak进行修饰
解决办法2、
可以在闭包的第一个大括号后面插入这段代码[weak self],后面的代码直接使用self?也能解决循环引用的问题
class MainVC: UITabBarController {
var callBack:((String)->())?
override func viewDidLoad() {
super.viewDidLoad()
// weak var weakSelf = self
PringtString { [weak self]
(text) in
print(text)
// 闭包中捕获self
self?.view.backgroundColor = UIColor.red
}
}
func PringtString(callBack:@escaping(String) -> ()) {
callBack("这个闭包返回一段文字")
// 控制器self强引用着callBack
self.callBack = callBack;
}