Block
block本質(zhì)是一個匿名函數(shù)竟块,底層是一個結(jié)構(gòu)體,里面包含屬性成員耐齐、isa函數(shù)指針等浪秘。
block主要是作為回調(diào)使用。
__block修飾符埠况,主要作用是把棧上數(shù)據(jù)復(fù)制到堆上耸携。在block函數(shù)體中,__block修飾的常量屬于指針引用辕翰,而沒有修飾符的常量屬于值引用夺衍。
int a = 10;
__block int b = 10;
block1 = ^{
NSLog(@"%@",a); //輸出a為10
NSLog(@"%@",b); //輸出b為20
}
a = 20;
b = 20;
block2 = ^{
NSLog(@"%@",a); //輸出a為20
NSLog(@"%@",b); //輸出b為20
}
block在聲明的時候,就會把外部變量復(fù)制喜命。所以block1復(fù)制的a是值沟沙,所以block1輸出的a為10,而block2輸出的值為20壁榕;而block1復(fù)制的b是指針矛紫,所以b重新賦值的時候,block1中的b也變了牌里,輸出b為20颊咬,而blcok2同理。
堆 棧
堆:內(nèi)存大牡辽、內(nèi)存地址不連續(xù)喳篇、由程序員管理
堆的內(nèi)存地址采用的是鏈表存儲,效率較慢态辛,分配方式只有動態(tài)分配
棧:內(nèi)存小麸澜、內(nèi)存地址連續(xù)、由系統(tǒng)管理奏黑、先進(jìn)先出
棧的效率較快炊邦,分配方式由靜態(tài)分配和動態(tài)分配
靜態(tài)分配是編譯器完成的,比如局部變量的分配攀涵。動態(tài)分配由alloca函數(shù)進(jìn)行分配铣耘,但是棧的動態(tài)分配和堆是不同的洽沟,他的動態(tài)分配是由編譯器進(jìn)行釋放以故,無需我們手工實現(xiàn)。
棧的內(nèi)存大小一般為2M
棧中儲存是常量和指針裆操。
比如局部變量 M* m = [[M alloc]init];
m的指針是存儲在棧上的怒详,而m的值是存儲在堆上的炉媒。
棧另一個名稱叫做函數(shù)棧,局部變量存放在棧中昆烁,整個程序都是執(zhí)行在主函數(shù)中吊骤,每次調(diào)用一個函數(shù),都是壓入一個棧區(qū)静尼。
比如函數(shù)A調(diào)用函數(shù)B白粉,會將函數(shù)A中的變量都壓入棧區(qū),調(diào)用函數(shù)B的時候會將整個函數(shù)A棧區(qū)作為一個模塊鼠渺,之后再把函數(shù)B中的變量壓入棧中鸭巴,當(dāng)B執(zhí)行完成,不再被調(diào)用拦盹,那么函數(shù)B的棧區(qū)出棧鹃祖。
一個函數(shù)利用GCD進(jìn)行延遲處理數(shù)據(jù),外部自由可控是否延遲處理執(zhí)行普舆,變?yōu)橐粋€通用函數(shù)恬口。
- (void)execAfter:(NSInteger)sec block:(void(^)(void))block {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
block();
});
}
以下幾種方式:
- (void)execAfter:(NSInteger)sec handle:(Handle*)handle block:(void(^)(void))block {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (handle.isExec) {
return;
}
block();
});
}
- (Handle*)execAfter:(NSInteger)sec block:(void(^)(void))block {
Handle* h = [Handle new];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (h.isExec) return;
block();
});
return h;
}