OC 的 Block 簡析1 - 三種類型


本文主要介紹 Block 的三種類型。

OC底層探索26、Block 原理

一、Block 是什么?

在 OC 文檔的 Working with Blocks 中:

  Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary.

Block 官方文檔: Block Programming Topics 中:

  As an optimization, block storage starts out on the stack—just like blocks themselves do.

block 是一個 OC 對象,但是它和普通的O從對象又不一樣。

block 默認在 棧上分內存,而我們一般的對象是在堆上。

二、block 有三種類型: 全局 / 棧 / 堆  block

1、全局block -  __NSGlobalBlock__

- (void)block3 {
    // 聲明: typedef  NSString *(^MyBlock)(NSString *str);
    MyBlock block = ^(NSString *str){
        
        NSLog(@"處理一些無關於外部屬性的事務");
        return str;
    };
    block(@"");
    NSLog(@"block類型%@",block);
}

2、棧block -  __NSStackBlock__

- (void)block2 {
    
    int a = 1;
    
    NSLog(@"block類型%@",^{ NSLog(@"block 0:%i", a); });
}

3、堆block -  __NSMallocBlock__

- (void)block1 {
    void (^blockObject)(void);
    blockObject = ^{ NSLog(@"block 0:%i", a); };
    blockObject();
    
    NSLog(@"block類型%@",blockObject);
}

從上面3部分代碼中,我們可看出三者區別:

全局block:block 沒有訪問任何外部變量的;

棧block: block 訪問了外部對象,但沒有copy操作;

堆block:相對於棧block來說:我們聲明定義了一個block同時訪問了外部變量則(不訪問就是全局)(不聲明定義就是棧),此過程本質就是棧-變->堆的過程,系統幫我們做了copy,棧的block遷移到了堆里。

4、關於堆block 詳解

代碼示例:

- (void)block1 {
    
    /* __block 允許block內部使用,
    */
    __block NSString *blockStr = @"局部str";
    MyBlock block = ^(NSString *str){
        
        /*
         block 內部操作:將對象 copy 了一個新的到堆上,指針不變,但指針指向新的對象
        */
        self->globalStr = @"block內修改全局";
         blockStr = str;

        NSLog(@"內globalStr== %@ %p %p",self->globalStr,self->globalStr,&self->globalStr);

        [self logstr:blockStr];
        
        return str;
    };
    
    NSLog(@"block類型%@",block);
    NSLog(@"外globalStr== %@ %p %p",globalStr,globalStr,&globalStr);
    NSLog(@"外blockStr== %@ %p %p",blockStr,blockStr,&blockStr);

    block(@"執行block,改局部str");
}
- (void)logstr:(NSString *)blockStr {
    
    NSLog(@"globalStr2== %@ %p %p",globalStr,globalStr,&globalStr);

    /*
     局部str,拿到外部,創建了一個新的指向它的指針
    */
    NSLog(@"blockStr2== %@ %p %p",blockStr,blockStr,&blockStr);
}

運行結果如圖:

 

我們可以看到,不論是函數中的局部變量 還是當前文件范圍的局部變量(注意:代碼里的‘全局’並非是真正的全局,只是為了用來區分函數內部變量), 在 block 內部進行使用,對象都不是外部的那個對象了,但是指向對象的指針不變 --> 即:指針指向的對象是一個copy出來的新的。如下圖:

 

從而,也可知,block內部會對我們的對象進行copy,但是指向對象的指針不變,指針指向對象會變成新的。 

而函數內部的局部變量被拿出去函數外部使用時,相當於 創建了一個新 的指向這個改變后對象的 指針。

 

待續... ...

以上。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM