Block 是一種特殊的數(shù)據(jù)類型,默認存儲在棧中,若對Block 進行一次Copy 則Block會進入堆中
1.Block訪問外部參數(shù)變量
--1.Block中可以訪問外界變量,會將外界變量Copy一份,供自己訪問,并不能修改外界變量的值,同理,由于是Copy一份,則在Blcok調(diào)用之前修改外界參數(shù)的值,同樣不會影響到Block內(nèi)部堆參數(shù)的引用,該值只是在Block聲明時有效
證明block中的參數(shù)是copy進該block的堆中
--2.Block 中可以定義和外界同名的變量,并且若在block中定義了和外界同名的變量,在Block中訪問的是Block中的變量
2.__block 修飾符
--1.要在Block中修改外界參數(shù),需要用__block 修飾該參數(shù)
但是,若在Block中修改了外界變量的值,會影響到外界變量的值
--2.__Block 可以防止Block在堆中時,對外部參數(shù)引用后Retain操作
3.__Block 關鍵字的實現(xiàn)原理
將代碼通過 終端 編譯成 c++代碼后發(fā)現(xiàn),在不加__Block關鍵字時,Block 在底層會被編譯成結(jié)構體,而參數(shù)a 是通過參數(shù)傳遞進結(jié)構體函數(shù),并將該參數(shù),賦值給結(jié)構體內(nèi)部的變量a
既 如果沒有添加__block 關鍵字聲明變量 該變量是值傳遞
內(nèi)部函數(shù)的調(diào)用
a變量的具體引用
添加__block關鍵字 后是對a變量地址的引用
添加__block關鍵字后,是對a變量地址的引用
4.MRC中的Block引用計數(shù)
默認情況下block 存儲在棧中,如果對block 進行一個copy操作,block 會轉(zhuǎn)移到堆中,
若block在棧中,且訪問了外界的對象,不會對對象進行retain操作
但是,若block在堆中,且訪問了外界對象,那么會外界的對象進行一次retain操作
需要通過Block_release()函數(shù)在dealloc函數(shù)中對Block 進行釋放 ,block中使用到的對象也都會收到該消息
在實際開發(fā)中,若在Block 中訪問了外界對象,一定要給變量添加__block 修飾符,這樣哪怕Block在堆中,也不會對外界對象進行Retain
5.copy Block 引發(fā)的循環(huán)引用
--1.MRC下
在堆中的Block內(nèi),引用自己對象本身,形成循環(huán)引用 利用 __block 修飾對象,在block內(nèi)不會進行retain
--2.ARC
在ARC環(huán)境中同理,被Copy的Block 在堆中,會對引用的外界參數(shù)進行強引用,這個時候需要將傳入Block內(nèi)的對象,轉(zhuǎn)化為若引用即可
Friend *p = [[Friend alloc]init];
下面這兩句代碼任選一句就可以了,但是官方推薦選用第一句
__weak typeof (p) weakp = p;
__unsafe_unretained typeof (p) weaka = p ;
p.testBlock =^{
[weakp run];
};
總結(jié)
1:什么是block?
block其實就是一個代碼塊,把你想要執(zhí)行的代碼封裝在這個代碼塊里,等到需要的時候再去調(diào)用。那block是OC對象嗎?答案是肯定的
官方文檔如下
2:block要用copy修飾,還是用strong
block本身是像對象一樣可以retain,和release。但是,block在創(chuàng)建的時候,它的內(nèi)存是分配在棧(stack)上,而不是在堆(heap)上。他本身的作于域是屬于創(chuàng)建時候的作用域,一旦在創(chuàng)建時候的作用域外面調(diào)用block將導致程序崩潰。
使用retain也可以,但是block的retain行為默認是用copy的行為實現(xiàn)的,
因為block變量默認是聲明為棧變量的,為了能夠在block的聲明域外使用,所以要把block拷貝(copy)到堆,所以說為了block屬性聲明和實際的操作一致,最好聲明為copy。
3:__block關鍵字的使用
在Block的{}體內(nèi),是不可以對外面的變量進行更改的,使用__block就能改變block塊中變量的值
4:__block和__weak有什么區(qū)別?
__block不管是ARC還是MRC模式下都可以使用,可以修飾對象,還可以修飾基本數(shù)據(jù)類型。__weak只能在ARC模式下使用,也只能修飾對象(NSString),不能修飾基本數(shù)據(jù)類型(int)。__block對象可以在block中被重新賦值,__weak不可以。