Block
block本質(zhì)是一個匿名函數(shù),底層是一個結構體,里面包含屬性成員、isa函數(shù)指針等。
block主要是作為回調(diào)使用。
__block修飾符,主要作用是把棧上數(shù)據(jù)復制到堆上。在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在聲明的時候,就會把外部變量復制。所以block1復制的a是值,所以block1輸出的a為10,而block2輸出的值為20;而block1復制的b是指針,所以b重新賦值的時候,block1中的b也變了,輸出b為20,而blcok2同理。
堆 棧
堆:內(nèi)存大、內(nèi)存地址不連續(xù)、由程序員管理
堆的內(nèi)存地址采用的是鏈表存儲,效率較慢,分配方式只有動態(tài)分配
棧:內(nèi)存小、內(nèi)存地址連續(xù)、由系統(tǒng)管理、先進先出
棧的效率較快,分配方式由靜態(tài)分配和動態(tài)分配
靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由alloca函數(shù)進行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進行釋放,無需我們手工實現(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中的變量壓入棧中,當B執(zhí)行完成,不再被調(diào)用,那么函數(shù)B的棧區(qū)出棧。
一個函數(shù)利用GCD進行延遲處理數(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;
}