block有三種型別,分別是
__nsglobalblock__:全域性block,程式被載入後被分配在程序資料段上(類似函式,位於text段),也就是常量,靜態建立的block。
__nsmallocblock__:在程序堆上分配的block,動態建立的block。
__nsstackblock__:程序棧上分配的block,動態建立的block。
在arc下我一直以為__nsstackblock__已經不會出現的了,事實上也並非如此,我們可以強行讓它出現,但實際開發中應該不會做這麼無聊的事。
先看看乙個demo。
——————————————————
- (void
)viewdidload ;
nslog
(@"%@"
, blocka);
intvalue = 10;
void
(^blockb)() = ^;
nslog
(@"%@"
, blockb);
void
(^ __weak
blockc)() = ^;
nslog
(@"%@"
, blockc);
}——————————————————
三個nslog列印的內容為:
<__nsglobalblock__: 0x105a730d0>
<__nsmallocblock__: 0x600000052c00>
<__nsstackblock__: 0x7fff5a18b7e0>
注意看它們的位址,__nsglobalblock__的位址明顯要短,因為它是在程序資料段上的。
blockc則是強行用__weak宣告讓其分配在棧上,這裡會看到乙個黃色的警告,大意就是指分配後就會被釋放。就是說viewdidload這個方法return後這個block就會被釋放。
動態分配和靜態分配的區分是在**?觀察一下就發現__nsglobalblock__型別是沒有捕獲區域性變數的,它只是列印一乙個字串。通過nsstring literal建立的字串是放在常量區的,也就是資料段上。全域性的block裡沒有引用任何堆或棧上的資料。另外如果將上面的例子中的int value = 10;改為const int value = 10;那麼blockb將變成__nsglobalblock__,這是因為const修飾下value裡的值會儲存在常量區即資料段上,也就是不違反原則,只要block literal裡沒有引用棧或堆上的資料,那麼這個block會自動變為__nsglobalblock__型別,這是編譯器的優化。
在屬性宣告上,我們一般會用copy修飾乙個block屬性。原因是什麼?
在mrr或mrc(兩個詞都是指同乙個玩意)中,block預設是在棧上建立的。如果我們將它賦值給乙個成員變數,如果成員變數沒有被copy修飾或在賦值的時候沒有進行copy,那麼在使用這個block成員變數的時候就會崩潰。因為棧上的出了作用域就被釋放掉了,copy操作可以將block從棧上copy到堆上
很早的時候mrc的block屬性都是在棧區的,copy之後就到堆區了
當前的arc的block屬性預設都在堆區,使用copy知識沿襲了歷史的習慣,使用strong也是沒有問題的
思考一下下面的**。
————————————————————————————————————
@property
(nonatomic
, weak
) void
(^block)();
- (void
)viewdidload ;
nslog
(@"%@"
, blockc);
_block = blockc;
}- (
ibaction
)action:(
id)sender
這**在mrc下是會崩潰的。但arc下就不會了,因為block預設就建立在堆上了。但是不是意味著arc不用寫copy來修飾block屬性呢?當然不是了,上面已經說了,我們是可以強行在arc上將乙個block建立在棧上的。
intvalue = 10;
void
(^ __weak
blockc)() = ^;
————————————————————————————————————
最後留乙個思考題,下面這種情況會不會崩毀?為什麼?
@property
(nonatomic
, weak
) void
(^block)();
- (void
)viewdidload ;
_block = blocka;
}- (
ibaction
)action:(
id)sender
上面的這個也是不會crash的,因為沒有引用臨時(內部或者外部變數),是個__nsglobalblock__型別的block,程式執行期間都不會釋放,所以根本就不用擔心野指標問題嘍!
ARC和MRC下Block的使用注意
1.是一段 塊,只在被呼叫的時候執行 類似於方法和函式 2.是一種資料型別 類似於 int nsstring 3.可以定義成臨時變數 4.可以當做引數傳遞 5.可以定義成屬性 6.是一種匿名函式 重要,只有函式體,沒有函式名 7.是乙個指向函式的指標 乙個指標物件,block的名字就是指標的位址 8...
block 的ARC和MRC中的區別
block屬性的宣告,首先需要用copy修飾符,因為只有copy後的block才會在堆中,棧中的block的生命週期是和棧繫結的,可以參考之前的文章 ios 非arc下返回block 另乙個需要注意的問題是關於執行緒安全,在宣告block屬性時需要確認 在呼叫block時另乙個執行緒有沒有可能去修改...
block在ARC和MRC中的區別
block在arc和mrc中的宣告引用有些區別.block可以儲存在棧中,也可以在堆中 預設儲存在棧中,不需要管理記憶體 儲存在堆中的block會對block進行retain操作 mrc block在堆中時,不想對block進行retain操作,前面加 block arc 前面加 weak或 uns...