1.使用Blocks
(1)block概念
Blocks是帶有自動變了(局部變量)的匿名函數(shù)抚芦。其寫法遵循BN范式
^ 返回值類型 參數(shù)列表 表達(dá)式
返回值類型可省略,參數(shù)列表亦可省略履怯。可以定一個Blocks變量來獲得匿名函數(shù)的使用權(quán)
如
int (^blk)(int) = ^(int count){return count+1};
我們可以作為參數(shù)傳遞Blocks變量,也可以返回Blocks類型變量,也可以使用typedef定義更方便使用Blocks變量
如
void func(int (^blk)(int)){}
int (^func())(int){
return ^(int count){return count+1};
}
typedef int (^blc_t)(int);
- block的代碼是內(nèi)聯(lián)的冗懦,效率高于函數(shù)調(diào)用
- block對于外部變量默認(rèn)是只讀屬性,要在block內(nèi)修改外部變量需要添加_block關(guān)鍵字修飾
- block被Objective-C看成是對象處理
block會捕獲在其定義時的變量值谬运,變量修改后并不會影響block中使用的變量隙赁。
如
{
int a = 10;
int (^blc)(int) = int ^(int count){return count+a;};
a++;
NSLog(@"%@",blc(5));//打印15,而不是16
}
變量的復(fù)制關(guān)系如下
block外變量引用梆暖,默認(rèn)是復(fù)制到block內(nèi)的readonly變量
[站外圖片上傳中...(image-7c89d1-1524555790555)]
對于用__ block修飾的外部變量引用伞访,block復(fù)制其引用地址來實現(xiàn)訪問
[站外圖片上傳中...(image-a85bf0-1524555790555)]
(2)block常見用法:
-
局部位置聲明一個Block型的變量
return_type (^blockName)(var_type) = ^return_type (var_type varName) { // ... }; blockName(var);
-
@interface聲明Block型屬性
@property(nonatomic, copy)return_type (^blockName) (var_type);
-
Block型作為形參
- (void)yourMethod:(return_type (^)(var_type))blockName;
-
內(nèi)聯(lián)用法,定義后立即調(diào)用,不常用
^return_type (var_type varName) { //... }(var);
-
遞歸調(diào)用
使用
__block
避免循環(huán)引用問題轰驳。__block return_type (^blockName)(var_type) = [^return_type (var_type varName) { if (returnCondition) { blockName = nil; return; } // ... // 【遞歸調(diào)用】 blockName(varName); } copy]; 【初次調(diào)用】 blockName(varValue);
-
作為返回值
- (return_type(^)(var_type))methodName { return ^return_type(var_type param) { // ... }; }
?
2.block原理
(1)數(shù)據(jù)結(jié)構(gòu)定義
block的數(shù)據(jù)結(jié)構(gòu)定義如下
[站外圖片上傳中...(image-894ad2-1524555790555)]
結(jié)構(gòu)體定義如下
#define BLOCK_DESCRIPTOR_1 1
struct Block_descriptor_1 {
unsigned long int reserved;
unsigned long int size;
};
struct Block_layout {
void *isa;
volatile int flags; // contains ref count
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor_1 *descriptor;
// imported variables
};
//Block-private.h
對于每個參數(shù)解釋如下
- isa: 對象指針
- flags: 記錄block的一些附加信息咐扭,包括引用計數(shù)
- reserved: 保留變量。
- invoke: 函數(shù)指針滑废,指向block函數(shù)實現(xiàn)地址蝗肪。
- descriptor:附加信息描述
//falgs bit位描述如下
enum {
BLOCK_DEALLOCATING = (0x0001), // runtime
BLOCK_REFCOUNT_MASK = (0xfffe), // runtime
BLOCK_NEEDS_FREE = (1 << 24), // runtime
BLOCK_HAS_COPY_DISPOSE = (1 << 25), // compiler
BLOCK_HAS_CTOR = (1 << 26), // compiler: helpers have C++ code
BLOCK_IS_GC = (1 << 27), // runtime
BLOCK_IS_GLOBAL = (1 << 28), // compiler
BLOCK_USE_STRET = (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE
BLOCK_HAS_SIGNATURE = (1 << 30) // compiler
};
從枚舉變量的定義可以看出flags的bit位作用,第0位表示釋放內(nèi)存標(biāo)志蠕趁,1-23bit作為引用計數(shù)值薛闪,24-31略過。
在OC中有三種block
- _NSConcreteGlobalBlock 全局的靜態(tài) block俺陋,不會訪問任何外部變量豁延。
- _NSConcreteStackBlock 保存在棧中的 block,當(dāng)函數(shù)返回時會被銷毀,ARC下不適用腊状。
- _NSConcreteMallocBlock 保存在堆中的 block诱咏,當(dāng)引用計數(shù)為 0 時會被銷毀。
下篇文章講解不同block的實現(xiàn)方式