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 返回數(shù)據(jù);
    };
    返回類型 接收數(shù)據(jù)的變量名 = block名(實參列表);// 使用block代碼

閉包的一般表達式

let 閉包名:(形參列表) -> 返回值類型 =  { (實參列表) -> 返回值類型 in
            表達式
            return 返回值
        }
        print(包名(實參列表)) // 使用閉包

Blcok相關(guān)語法

BLock類型變量在BLock語法下,一旦使用了BLock就相當于生成了可復制給BLock類型變量的值,Block既指源碼中給你的BLock語法也指有BLock生成的值

typedef int(^blk)(int); // 此時blk是一個BLock數(shù)據(jù)類型
    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);
// 執(zhí)行結(jié)果是 val is 1

在以下代碼是不會報錯:

NSMutableArray *arrayM = [NSMutableArray array];
    void(^blk)(void) = ^(void) {
        id obj = [[NSObject alloc] init];
        [arrayM addObject:obj];
    };
    blk();

如果外部變量沒有使用__block修飾,對該變量進行賦值就會報錯,但是對數(shù)組進行添加是沒有對數(shù)組進行賦值,是不會報錯。

block作為參數(shù)的時候:

- (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

閉包相關(guān)語法

利用typealias為閉包類型定義別名
typealias類似OC語法中的typedef
用法很簡單,直接用 = 賦值就行了.

    // 定義一個沒有參數(shù)也沒有返回值的別名
    typealias Nothing = () -> ()
    // 如果沒有返回值也可以這樣寫
    typealias Anything = () -> Void
    // 接收一個參數(shù)沒有返回值
    typealias PringtNumber = (Int) -> ()
    // 有參數(shù),有返回值的
    typealias Add = (Int, Int) -> (Int)
    typealias Add = (_ num1: Int, _ num2: Int) -> (Int)
    // 創(chuàng)建一個Add類型的閉包常量addCloser1
    let addCloser1:Add
    // 為已經(jīng)創(chuàng)建好的常量進行賦值
    addCloser1 = { 
        (_ num1:Int, _ num2: Int) -> Int in
        return num1 + num2
    }
    // 調(diào)用閉包并接收返回值
    let result = addCloser1(1,2)

2.閉包類型申明和變量的穿件合并在一起

let Add:(_ num1: Int, _ num2: Int) -> (Int)
Add = { 
(_ num: Int, _ num2: Int) -> (Int) in
    return num + num2
}
// 調(diào)用閉包并接收返回值
let result  = Add(2,3)

3.省略閉包接收的形參、省略閉包體中返回值

let Add:(Int,Int) -> (Int)
Add = { 
(num,num2) -> (Int) in
    return num + num2
}
// 調(diào)用閉包并接收返回值
let result  = Add(2,3)

4.在3的基礎(chǔ)上繼續(xù)精簡

let Add:(Int, Int) -> (Int)
Add = 
    { (num, num2) in
        return num + num2
}
// 調(diào)用閉包并接收返回值
let result  = Add(2,3)

5.如果閉包沒有參數(shù)可以省略in

// 創(chuàng)建一個 () -> (String)類型的閉包常量:addCloser1并賦值
let addCloser1:() -> (String) = {
    return "這個閉包沒有參數(shù),但是有返回值"
}
// 調(diào)用閉包并接收返回值
let result = addCloser1()

6.簡寫的實際參數(shù)名

// 創(chuàng)建一個(String,String) -> (String) 類型的閉包常量:addCloser1并賦值
let addCloser1:(String, String) -> (String) = {
    return "閉包的返回值是:\($0),\($1)"
}
// 調(diào)用閉包并接受返回值
let result  = addCloser1("Hello", "Swift")

$0和$1分別表示閉包的第一個和第二個String類型的實際參數(shù)

閉包作為函數(shù)的參數(shù)

1.尾隨閉包
//函數(shù)的定義
func combie2(times: Int, handle:(String, String) -> (Void)) -> Void {
    for i in 1...times {
        handle("\(i)", "456")
    }
}
// 函數(shù)的調(diào)用
combie2(times: 3) { (str1, str2) -> (Void) in
    print("\(str1),\(str2)")
}

如果函數(shù)只有唯一的閉包參數(shù),沒有其他的參數(shù)可以省略函數(shù)的小括號

func combie2(handle:(String, String) -> (Void)) -> Void {
        handle("123", "456")
    }
combie2 { (str1, str2) -> (Void) in
    print("\(str1), \(str2)")
}
2.逃逸閉包

后續(xù)補充。。。

在Swift中使用閉包不當可能引起循環(huán)強引用

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?也能解決循環(huán)引用的問題

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;
        
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容