深入學習block

来源:http://www.cnblogs.com/wuqh-iOS/archive/2016/04/27/5438536.html
-Advertisement-
Play Games

首先,什麼是block:block其實就是一個代碼塊,把你想要執行的代碼封裝在這個代碼塊里,等到需要的時候再去調用。那block是OC對象嗎?答案是肯定的 做一道很簡單的關於block的測試題。: 這道題是我公司面試題中的一道,來面試的都是至少兩年工作經驗的,但是很鬱悶,這道題絕大多數人寫的都是6。 ...


 

首先,什麼是block:block其實就是一個代碼塊,把你想要執行的代碼封裝在這個代碼塊里,等到需要的時候再去調用。那block是OC對象嗎?答案是肯定的

做一道很簡單的關於block的測試題。:

1 //
2     int (^testBlock) (int) = ^(int num) {
3         return num++;
4     };
5     NSLog(@"%d", testBlock(testBlock(testBlock(3))));

這道題是我公司面試題中的一道,來面試的都是至少兩年工作經驗的,但是很鬱悶,這道題絕大多數人寫的都是6。。正確結果為:3。

以下講解的內容均是ARC環境下。

一、block的分類
  • NSStackBlock:棧block
  • NSMallocBlock:堆block
  • NSGlobalBlock:全局block

1.NSStackBlock: 特點:生命周期由系統控制,函數返回即銷毀 用到局部變數、成員屬性\變數,且沒有強指針引用的block都是棧block
//棧block
    int i = 0;
    NSLog(@"%@",^{NSLog(@"%d",i);});//輸出結果 __NSStackBlock__: 0x7fff57aada78>
註意:不是沒有強指針(copy或strong)引用的block,就是棧block,也有可能是全局block(下麵會介紹什麼是全局block)。   2.NSMallocBlock: 特點:沒有強指針引用即銷毀,生命周期由程式員手動管理
棧block如果有強指針引用或copy修飾的成員屬性引用就會被拷貝到堆中,變成堆block
//堆block
     int j = 0;
    void(^mallocBlock)() = ^ {
        NSLog(@"%d",j);
    };
    NSLog(@"%@",mallocBlock);//輸出結果 <__NSMallocBlock__: 0x7f8cd351db80>
上面代碼也沒用看到strong 或 copy修飾符,但是為什麼會強引用的,因為在ARC環境下,我們在聲明變數的時候,前面是會被預設加上 __strong 修飾符的。所以我們在ARC下聲明的Block一般都是堆block。   3.NSGlobalBlock:  特點:命長,有多長?很長很長,人在塔在(應用程式在它就在) 沒有用到外界變數,或者只用到全局變數、靜態(static)變數的block就是全局block 對於全局block,用weak,strong,還是copy修飾都是可以的。(但最好不用用weak)
//全局block
    void (^globalBlock) () = ^ {
        NSLog(@"%d",staticNum);
    };
    NSLog(@"%@",globalBlock); //輸出結果 <__NSGlobalBlock__: 0x108152110>

註意:如果block中沒有用到外界變數,不管他是用什麼修飾符修飾,他都是全局block!

例如:

void (^global2Block) () = ^ {
        NSLog(@"globalBlock");
    };
    NSLog(@"%@",global2Block); // 輸出結果 <__NSGlobalBlock__: 0x1023a0150>

 

二、block對外界變數的捕獲

1.1 基本數據類型:局部變數

     block會拷貝該變數的值當做常量使用,外界修改變數的值不會影響block內部,且block內部不能對其修改

     block內部修改外界變數i的值直接報錯,如果想要修改,可以在int a = 0前面加上關鍵字__block,此時i等效於全局變數或靜態變數

  int a = 0;
    void (^block1)() = ^ {
//        a++ 直接修改a會報錯
        NSLog(@"a = %d",a);
    };
    a++;
    block1(); //輸出結果 a = 0;
    
    __block int b = 0;
    void (^block2) () = ^ {
        NSLog(@"b = %d",b); // 輸出結果 b = 0;
        b = 2;
    };
    block2();
    NSLog(@"b = %d",b); //輸出結果 b = 2;

1.2 基本數據類型:成員變數(實例變數),靜態變數,全局變數

   block直接訪問變數地址,在block內部可以修改變數的值,並且外部變數被修改後,block內部也會跟著變

self.num = 1;
    self.num ++;
    void (^block3) () = ^ {
        self.num++;
    };
    block3();
    NSLog(@"%d",self.num);//輸出結果為 3

 2.1 指針類型: 局部變數

     block會複製一份指針並強引用指針所指對象,且內部不能修改指針的指向,但是可以修改指針所指向對象的值

  NSMutableString *str = @"abc".mutableCopy;
    void (^block4) () = ^ {
//        str = @"def"; 報錯
        [str appendString:@"def"];
        NSLog(@"str = %@",str);
    };
    str = @"123".mutableCopy;
    block4(); //輸出結果為 "adbdef"

2.2 指針類型: 成員變數(實例變數),靜態變數,全局變數

     block不會複製指針,但是會強引用該對象,內部可修改指針指向,block會強引用成員屬性\變數所屬的對象,這也是為什麼block內部用到self.xxx_xxx可能會引起迴圈引用的原因

static NSString *staticStr = @"abc";
    void (^block5) () = ^ {
        NSLog(@"staticStr = %@",staticStr);
        staticStr = @"def";
        NSLog(@"staticStr = %@",staticStr);
    };
    staticStr = @"123";
    block5();
    //輸出結果為 staticStr = 123  staticStr = def

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Underfined類型的值:underfined(只有一個) 1/聲明未初始化 e.g.:var msg;-->msg == underfined:true 2/申明並值初始化為underfined e.g.:var msg = underfined;-->msg == underfined:tr ...
  • 1、頁面載入成功後,點擊選中或取消選中該checkbox,checkbox屬性里的checked屬性不會根據該checkbox是否選中而變化 2、checkbox里的onchange或onclick方法里用jquery的attr方法獲取checked是看得到的checked屬性的值與它是否給鉤上沒有 ...
  • 相信很多小伙伴會遇到這種問題,用ajax做非同步請求的時候,在IE瀏覽器下,並沒有發送出去。但是相關程式確實執行了。為什麼呢? 原來這是IE緩存方式的原因,所以呢,用下邊的解決方案吧。 1.在請求的URL後邊加上隨機數。Math.random(); ...
  • //格式化日期 function setDate(date){ y=date.getFullYear(); m=date.getMonth()+1; d=date.getDate(); m=m<10?"0"+m:m; d=d<10?"0"+d:d; return y+"-"+m+"-"+d; } / ...
  • <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title> <!--先載入css --> <link rel="stylesheet" href="style.css"></head><body> ...
  • JQuery AJAX中遇到這樣一個問題,參數中包含特殊字元,比如&'#@等, 這時執行AJAX的時候就會出問題,因為所傳的參數變了.看個示例就明白: 方案一: 上面執行的ajax就是非同步刪除一個name為 11&abd 的數據 當請求到ajax.ashx頁面時,我們獲取到的name參數為11 執行 ...
  • 打開一個已經下載好的文件有很多種方法,例如打開一個MP4文件,你可以選擇AVPlayer,MPMovieplayerViewController,QuickLook,或者是百度影音等等,方法不止一種,以需求而定. QuickLook是快速查看,平時使用Mac電腦就會比較熟悉.不依賴完整的應用,而是提 ...
  • 使用場景 一個半透明的框上面 放了一些label 改變半透明view的alpha 結果 label的 alpha 也跟著改變了。 其實不用那麼麻煩 給你們UI 要一個色值也可以 不需要 自己寫了 這樣比較好一點 。 既然 這樣寫了 出現問題 就解決問題。 針對放在一個view的label 字體顏色的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...