1、定義面試
(1) Block是OC中的一種數據類型,在iOS開發中被普遍使用數組
(2) ^是Block的特有標記函數
(3) Block的實現代碼包含在{}之間atom
(4) 大多狀況下,之內聯inline函數的方式被定義和使用指針
(5) Block與C語言的函數指針有些類似,但使用起來更加靈活對象
例如:作用域
void(^demoBlock)() = ^ {開發
NSLog(@"demo Block");編譯
};table
int(^sumBlock)(int, int) = ^(int x, int y) {
return x + y;
};
格式說明:
(返回類型)(^塊名稱)(參數類型) = ^(參數列表) {代碼實現};
若是沒有參數,等號後面參數列表的()能夠省略
2、常見相關面試題
Block可使用在定義以前聲明的局部變量:
int i = 10;
void(^myBlock)() = ^{
NSLog(@"%d", i);
};
i = 100;//實際上並沒效果
myBlock();
輸出結果爲:10
注意:
(1) 在定義Block時,會在Block中創建當前局部變量內容的副本(拷貝)
(2) 後續再對該變量的數值進行修改,不會影響Block中的數值
(3) 若是須要在block中保持局部變量的數值變化,須要使用__block關鍵字
(4) 使用__block關鍵字後,一樣能夠在Block中修改該變量的數值
3、當作參數傳遞
Block能夠被當作參數直接傳遞:
NSArray *array = @[@"張三", @"李四", @"王五", @"趙六"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"第 %d 項內容是 %@", (int)idx, obj);
if ([@"王五" isEqualToString:obj]) {
*stop = YES;
}
}];
說明:遍歷並NSLog() array中的內容,當obj 爲"王五"時中止遍歷
4、使用局部變量
在被當作參數傳遞時,Block一樣可使用在定義以前聲明的局部變量:
int stopIndex = 1;
NSArray *array = @[@"張三", @"李四", @"王五", @"趙六"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"第 %d 項內容是 %@", (int)idx, obj);
if ([@"王五" isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
}
}];
注意,默認狀況下,Block外部的變量,在Block中是隻讀的!
BOOL flag = NO;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([@"王五" isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
flag = YES; // 編譯錯誤!!!
}
}];
5、__block關鍵字
若是要修改Block以外的局部變量,須要使用__block關鍵字
__block BOOL flag = NO;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([@"王五" isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
flag = YES; // 如今能夠修改了!!!
}
}];
提示:無需使用__block關鍵字,在塊代碼中能夠修改爲員變量的數值(比較少用)
6、傳遞對象
對象傳遞進Block的方式
NSString *stopName = @"王五";
NSArray *array = @[@"張三", @"李四", @"王五", @"趙六"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"第%d項內容是%@", (int)idx, obj);
if ([stopName isEqualToString:obj] || idx == stopIndex) {
*stop = YES;
}
}];
爲保證Block中的代碼正常運行,在將stopName的指針傳遞給Block時,Block會自動對stopName的指針作強引用
7、Block在棧區工做示意圖
8、typedef
可使用typedef定義一個Block的類型,便於在後續直接使用
typedef double(^MyBlock)(double, double);
MyBlock area = ^(double x, double y) {
return x * y;
};
MyBlock sum = ^(double a, double b) {
return a + b;
};
NSLog(@"%.2f", area(10.0, 20.0));
NSLog(@"%.2f", sum(10.0, 20.0));
說明:
(1) typedef是關鍵字用於定義類型,MyBlock是定義的Block類型
(2) area、sum分別是MyBlock類型的兩個Block變量。
儘管,typedef能夠簡化Block的定義,但在實際開發中並不會頻繁使用typedef關鍵字。
這是由於Block具備很是強的靈活性,尤爲在以參數傳遞時,使用Block的目的就是爲了當即使用。
官方的數組遍歷方法聲明以下:
而若是使用typedef,則須要:
(1) typedef void(^EnumerateBlock)(id obj, NSUInteger idx, BOOL *stop);
(2) - (void)enumerateObjectsUsingBlock:(EnumerateBlock)block;
而最終的結果倒是,除了定義類型以外,EnumerateBlock並無其餘用處。
9、添加到數組
既然Block是一種數據類型,那麼能夠將Block當作比較特殊的對象
#pragma mark 定義並添加到數組
@property (nonatomic, strong) NSMutableArray *myBlocks;
int(^sum)(int, int) = ^(int x, int y) {
return [self sum:x y:y];
};
[self.myBlocks addObject:sum];
int(^area)(int, int) = ^(int x, int y) {
return [self area:x y:y];
};
[self.myBlocks addObject:area];
#pragma mark 調用保存在數組中的Block
int(^func)(int, int) = self.myBlocks[index];
return func(x, y);
10、循環引用
@property (nonatomic, strong) NSMutableArray *myBlocks;
#pragma mark 將代碼改成調用self的方法
int(^sum)(int, int) = ^(int x, int y) {
return [self sum:x y:y];
};
[self.myBlocks addObject:sum];
#pragma mark 對象被釋放時自動調用
- (void)dealloc
{
NSLog(@"DemoObj被釋放");
}
十一、解除循環引用
局部變量默認都是強引用的,離開其所在的做用域以後就會被釋放。
使用__weak關鍵字,能夠將局部變量聲明爲弱引用
__weak DemoObj *weakSelf = self;
在Block中引用weakSelf,則Block不會再對self作強引用
int(^sum)(int, int) = ^(int x, int y) {
return [weakSelf sum:x y:y];
};