objc的“block”和Swift的“闭包"表达式

要理解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;
        
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容