block屬性的宣告,首先需要用copy修飾符,因為只有copy後的block才會在堆中,棧中的block的生命週期是和棧繫結的,可以參考之前的文章(ios: 非arc下返回block)。
另乙個需要注意的問題是關於執行緒安全,在宣告block屬性時需要確認「在呼叫block時另乙個執行緒有沒有可能去修改block?」這個問題,如果確定不會有這種情況發生的話,那麼block屬性宣告可以用nonatomic。如果不肯定的話(通常情況是這樣的),那麼你首先需要宣告block屬性為atomic,也就是先保證變數的原子性(objective-c並沒有強制規定指標讀寫的原子性,c#有)。
比如這樣乙個block型別:
typedefvoid
(^myblocktype)(
int);
屬性宣告:
@property(copy
) myblocktype
myblock;
這裡arc和非arc宣告都是一樣的,當然注意在非arc下要release block。
但是,有了atomic來保證基本的原子性還是沒有達到執行緒安全的,接著在呼叫時需要把block先賦值給本地變數,以防止block突然改變。因為如果不這樣的話,即便是先判斷了block屬性不為空,在呼叫之前,一旦另乙個執行緒把block屬性設空了,程式就會crash,如下**:
if(self
.myblock
)
所以正確的**是(arc):
myblocktypeblock =
self
.myblock
;//block
現在是本地不可變的
if(block)
在非arc下則需要手動retain一下,否則如果屬性被置空,本地變數就成了野指標了,如下**:
//非arc
myblocktype
block = [
self
.myblock
retain
];if
(block)
[block
release
];
返回目錄
迴圈引用是另乙個使用block時常見的問題。
在arc下,由於__block抓取的變數一樣會被block retain,所以必須用弱引用才可以解決迴圈引用問題,ios 5之後可以直接使用__weak,之前則只能使用__unsafe_unretained了,__unsafe_unretained缺點是指標釋放後自己不會置空。示例**:
//ios 5之前可以用
__unsafe_unretained
//__unsafe_unretained typeof(self) weakself = self;
__weak
typeof
(self
) weakself =
self
;self
.myblock
= ^(
intparamint)
;
在非arc下,顯然無法使用弱引用,這裡就可以直接使用__block來修飾變數,它不會被block所retain的,參考**:
//非arc
__block
typeof
(self
) weakself =
self
;self
.myblock
= ^(
intparamint)
;
3.1 block在arc和mrc中的情況
/**block可以儲存在棧中,也可以在堆中
預設儲存在棧中,不需要管理記憶體
儲存在堆中的block會對block進行retain操作
*///(mrc)block在堆中時,不想對block進行retain操作,前面加__block
//(arc)前面加__weak或__unsafe_unretained
//__weak和__unsafe_unretained的區別:__weak則在釋放時會對物件賦值nil,後者不會
//block_copy使棧中的block轉移到堆中,並對block會引用的物件進行retain操作
//避免block引用的物件進行retain操作,在引用物件宣告時前面加__block
[objc]view plain
copy
print?
void
blockarc_mrc();
nslog(@"block引用後:d retaincount = %zd"
,d.retaincount
);
block_copy(myblock);
nslog(@"block copy後:d retaincount = %zd"
,d.retaincount
);
block_release(myblock);
nslog(@"block release後:d retaincount = %zd"
,d.retaincount
);
myblock();
nslog(@"block呼叫後:d retaincount = %zd"
,d.retaincount
);
[drelease
];
}
3.2 block中引用成員變數情況
// 1.沒有呼叫d.age時,不需要__block
// 2.呼叫d.age時.必須要__block
[objc]view plain
copy
print?
void
copyblock() ;
nslog(@"block引用後:d retaincount = %zd"
,d.retaincount
);
d.myblock
();
nslog(@"block呼叫後:d retaincount = %zd"
,d.retaincount
);
[drelease
];
}
-- end
block在ARC和MRC中的區別
block在arc和mrc中的宣告引用有些區別.block可以儲存在棧中,也可以在堆中 預設儲存在棧中,不需要管理記憶體 儲存在堆中的block會對block進行retain操作 mrc block在堆中時,不想對block進行retain操作,前面加 block arc 前面加 weak或 uns...
ARC和MRC下Block的使用注意
1.是一段 塊,只在被呼叫的時候執行 類似於方法和函式 2.是一種資料型別 類似於 int nsstring 3.可以定義成臨時變數 4.可以當做引數傳遞 5.可以定義成屬性 6.是一種匿名函式 重要,只有函式體,沒有函式名 7.是乙個指向函式的指標 乙個指標物件,block的名字就是指標的位址 8...
ARC和MRC下的block的記憶體分布詳解
block有三種型別,分別是 nsglobalblock 全域性block,程式被載入後被分配在程序資料段上 類似函式,位於text段 也就是常量,靜態建立的block。nsmallocblock 在程序堆上分配的block,動態建立的block。nsstackblock 程序棧上分配的block,...