iOS 非ARC下返回Block

2021-06-29 03:38:44 字數 2406 閱讀 8361

首先,對於沒有引用外部變數的block,無論在arc還是非arc下,型別都是__nsglobalblock__,這種型別的block可以理解成一種全域性的block,不需要考慮作用域問題。同時,對他進行copy或者retain操作也是無效的,比如這樣乙個返回block的函式:

typedef

int(^myblock)();

myblock

func()

;}

在非arc下執行如下**:

//

非arc

myblock

block =

func

();nslog

(@"%d"

, block());

nslog

(@"%@"

, [block

class

]);myblock

block2 = [block

copy

];//copy

操作對__nsglobalblock__

型別無效

nslog

(@"%d"

, block == block2);

輸出:

123

__nsglobalblock__

1

可以看到,copy後的block和原來是同乙個物件的。

而對於引用了外部變數的block,如果沒有對他進行copy,他的作用域只會在宣告他的函式棧內(型別是__nsstackblock__),如果想在非arc下直接返回此類block,xcode會提示編譯錯誤的,如下圖:

(xcode提示returning block that lives on the local stack)

而在arc環境下,上述**會編譯通過,因為arc會自動加入copy操作。

比如可以在arc下執行如下**:

//arc

myblock

block =

func

();nslog

(@"%d"

, block());

nslog

(@"%@"

, [block

class

]);

輸出:

123

__nsmallocblock__

型別是__nsmallocblock__,說明block已經被copy到了堆中了。

當然其實在非arc下,也可以使上面有錯誤的函式編譯通過。如下**:

typedef

int(^myblock)();

myblock

func()

;return

ret;

}

我們把原來的返回值賦給乙個變數,然後再返回這個變數,就可以編譯通過了。不過雖然編譯通過了,這個返回的block作用域仍是在函式棧中的,因此一旦函式執行完畢後再使用這個block很可能會引發bad_access錯誤。

所以在非arc下,必須把block複製到堆中才可以在函式外使用block,如下正確的**:

typedef

int(^myblock)();

myblock

func()

copy

];}

我們可以直接通過輸出變數的指標,就可以驗證block被copy後,他所引用的變數被複製到了堆中的情況,如下**(非arc下):

//

非arc

void

func()

;block = [block

copy

];block();

nslog

(@"%@"

, @"=== block copy後"

);nslog

(@"&a = %p, &b = %p"

, &a, &b);

nslog

(@"a = %d, b = %d"

, a, b);

[block

release

];}

輸出:

=== block copy前

&a = 0x7fff5fbff8bc, &b = 0x7fff5fbff8b0

=== block

&a = 0x100201048, &b = 0x100201068

a = 123, b = 456

=== block copy後

&a = 0x7fff5fbff8bc, &b = 0x100201068

a = 123, b = 456

可以看到,在block執行中,他所引用的變數a和b都被複製到了堆上。而被標記__block的變數事實上應該說是被移動到了堆上,因此,當block執行後,函式棧內訪問b的位址會變成堆中的位址。而變數a,仍會指向函式棧內原有的變數a的空間。

非ARC下返回Block

首先,對於沒有引用外部變數的block,無論在arc還是非arc下,型別都是nsglobalblock,這種型別的block可以理解成一種全域性的block,不需要考慮作用域問題。同時,對他進行copy或者retain操作也是無效的,比如這樣乙個返回block的函式 typedef int mybl...

ARC和非ARC下使用Block屬性的問題

block屬性的宣告,首先需要用copy修飾符,因為只有copy後的block才會在堆中,棧中的block的生命週期是和棧繫結的。另乙個需要注意的問題是關於執行緒安全,在宣告block屬性時需要確認 在呼叫block時另乙個執行緒有沒有可能去修改block?這個問題,如果確定不會有這種情況發生的話,...

Block在ARC和非ARC中的使用

1 block是事先封裝好的一段 快,在需要的時候呼叫block執行 block底層是指向結構體的指標,編譯器會將block的內部 生成c語言對應的函式 2 block預設是存放在棧中的 開發人員不需要管理記憶體 儲存在棧中的block不會對引用的物件進行retain 3 非arc 對block進行...