官术网_书友最值得收藏!

2.12 塊(block)

塊的使用是Objective-C中比較有特點的功能之一,它為我們提供了一種更加靈活的代碼結構。

圖2-17 塊的應用

下面的代碼聲明了一個名為factory的塊,它包括兩個int類型的參數,以及int類型的返回值,看上去和函數非常相似(實際上,在Swift中,就是使用函數類型取代了塊的功能)。

    int(^factory)(int num1, int num2)

實際應用中,我們經常會將一個塊的定義賦值到一個塊變量,如下面的代碼,我們分別定義了兩個塊,并賦值給兩個塊變量(factory1和factory2)。

    // 加法工廠塊
    int(^factory1)(int, int) = ^int (int num1, int num2) {
        return num1 + num2;
    };
    // 減法工廠塊
    int(^factory2)(int, int) = ^int (int num1, int num2) {
        return num1- num2;
    };

我們可以看到,塊變量的格式初看起來可能有些奇怪,它同時包含了塊變量名、返回值類型和參數類型。

在賦值運算符后面則是塊的具體實現,此時不使用塊的名稱,但返回值和參數類型必須與塊變量的定義相同,并且需要指定參數名稱。

接下來,我們看一看如何使用這兩個塊,如下面的代碼。

    #import <Foundation/Foundation.h>
    int numberFactory(int(^factory)(int, int), int num1, int num2)
    {
        return factory(num1, num2);
    }
    int main(int argc , const char * argv[])
    {
        @autoreleasepool {
            // 加法工廠
            int(^factory1)(int, int) = ^int (int num1, int num2) {
                return num1 + num2;
            };
            // 減法工廠
            int(^factory2)(int, int) = ^int (int num1, int num2) {
                return num1- num2;
            };
            // 調用工廠塊
            int num1 = 10;
            int num2 = 6;
            NSLog(@"%i\n", numberFactory(factory1, num1, num2)); //16
            NSLog(@"%i\n", numberFactory(factory2, num1, num2)); //4
        }
        return 0;
    }

代碼中,我們首先創建了函數numberFactory(),請注意它的第一個參數,定義為一個塊類型,其格式為int類型的返回值,以及兩個int類型的參數。第二和第三個參數則代入兩個int類型的數值。

再看numberFactory()函數中的實現代碼,我們可以看到,這個函數的功能是依靠塊的執行來處理兩個int數據(第二個參數和第三個參數)。

在main()函數中,調用了兩次numberFactory()函數,不同之處在于它們的參數指定為不同的工廠塊,這樣也就實現了對兩個數值的不同的操作,也就是分別執行了加法運算和減法運算。

這就是塊的主要功能,我們可以使用相同的定義(塊類型)實現不同的功能,也就是加什么塊干什么活的含義了!

實際上,如果塊只需要使用一次,我們并不需要單獨定義,而是可以在使用的地方直接定義,如下面的代碼就是通過numberFactory()函數進行乘法運算的。

    int result = numberFactory(
        ^int (int num1, int num2) {
            return num1 * num2;
        },
        num1, num2);
    NSLog(@"%i", result);  //60

在這里,只是顯示了塊的簡單使用,在Foundation、Sprite Kit等框架中的開發資源中,可以看到很多關于塊的使用,我們可以在實際應用中逐漸理解塊的意義,并能夠正確應用。

此外,如果需要在塊中修改函數或方法內定義的變量,則必須在變量定義時使用__block標識,先看下面的代碼。

    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            int num = 10;
            void (^addOne)(void) = ^void(void){
                num++; // 出錯
            };
            addOne();
            NSLog(@"num = %i", num);
        }
        return 0;
    }

代碼執行會出錯,我們應該將變量num的定義修改為:

    __block int num = 10;

這樣,代碼就會正確執行,并顯示“num = 11”。

此外,如果塊沒有返回值和參數,還可以更簡單地定義,如前面的addOne塊就可以寫成:

    void (^addOne)() = ^{
        num++;
    };

關于塊,最后需要說明的是,塊應該定義在函數或方法內部。同時,塊也可以作為參數來使用,這實際上就是實現訪問者模式的重要方法,其基本原理是,在定義函數或方法時,并不能確定其中的一部分功能是如何實現的,但在調用這個函數或方法時,可能通過塊參數傳遞具體的實現代碼,我們會在后續的實踐中看到在參數中傳遞塊的實際應用。

主站蜘蛛池模板: 陇南市| 清水河县| 安吉县| 崇礼县| 大洼县| 鹤壁市| 林芝县| 和静县| 九寨沟县| 黔西县| 且末县| 巴楚县| 西宁市| 大方县| 双峰县| 清河县| 武强县| 湟中县| 怀远县| 天峻县| 鄂托克旗| 获嘉县| 南宁市| 印江| 萍乡市| 拜泉县| 柘城县| 建宁县| 虹口区| 太仓市| 无锡市| 根河市| 瑞安市| 郸城县| 清远市| 红安县| 淄博市| 万载县| 高安市| 张家口市| 大渡口区|