Block技術(shù)合集
iOS - Block變量截獲
1. Block定義
//聲明定義
int(^ sumOfNumbers)(int a, int b) = ^(int a, int b) {
return a + b;
};
int sum = sumOfNumbers(1, 2);
NSLog(@"sum = %d", sum);
//打印
2021-05-01 11:04:05.920543+0800 BlockDemo[18351:6429226] sum = 3
這段代碼等號(hào)左側(cè)聲明一個(gè)名為sumOfNumbers的代碼塊,名稱前用^符號(hào)表示后面的字符串是block的名稱嵌洼。最左側(cè)的int表示這個(gè)block的返回值案疲,括號(hào)中間表示這個(gè)block的參數(shù)列表,這里接收兩個(gè)int類型的參數(shù)麻养。 而在等號(hào)右側(cè)表示這個(gè)block的定義褐啡,其中返回值是可以省略的,編譯器會(huì)根據(jù)上下文自動(dòng)補(bǔ)充返回值類型鳖昌。使用^符號(hào)銜接著一個(gè)參數(shù)列表备畦,使用括號(hào)包起來,告訴編譯器這是一個(gè)block许昨,然后使用大括號(hào)將block的代碼封裝起來懂盐。
2. Block寫法
return_type
表示返回的對(duì)象/關(guān)鍵字等(通常是void
)blockName
表示block
的名稱var_type
表示參數(shù)的類型varName
表示參數(shù)名稱
1. 做為局部變量
return_type (^blockName)(var_type) = ^return_type (var_type varName) {
// ...
};
blockName(var);
int(^ sumOfNumbers)(int a, int b) = ^(int a, int b) {
return a + b;
};
2. 做為屬性
@property (copy) return_type (^blockName) (var_type);
@property (nonatomic, copy) void(^ didLoginSuccess)(NSString *username);
@property (nonatomic, copy) void(^ didLoginFailed)(void);
3. 定義方法時(shí),做為Block型的形參數(shù)
- (void)yourMethod:(return_type (^)(var_type))blockName;
- (void)sumOfA:(int)a B:(int)b sumBlock:(void(^)(int sum))sumBlock {
int sum = a + b;
sumBlock(sum);
}
- (void)login:(void(^)(void))completion {
completion();
}
4. Block作為實(shí)參
Block作為參數(shù)使用糕档,常見于各框架之中莉恼,比如在封裝一個(gè)類時(shí),當(dāng)做什么事情由外界去決定,什么時(shí)候調(diào)用由自己的類決定時(shí)俐银,這時(shí)候就需要將block作為參數(shù)使用尿背。
[someObject doSomethingWithBlock: ^return_type (var_type varName)
{
//...
}];
以自定義一個(gè)簡(jiǎn)單的工具類CalculatorManager為例:
//
// CalculatorManger.h
// BlockDemo
//
// Created by Ternence on 2021/5/1.
//
#import <Foundation/Foundation.h>
@interface CalculatorManger : NSObject
//計(jì)算結(jié)果值
@property (nonatomic, assign) int result;
+ (instancetype)sharedManager;
//block作為參數(shù)時(shí)格式與其它類型定義時(shí)一致,都是(類型)變量名悉患,看起來有些暈人
- (void)calculate:(int(^)(int))calculateBlock;
@end
//
// CalculatorManger.m
// BlockDemo
//
// Created by Ternence on 2021/5/1.
//
#import "CalculatorManger.h"
static int defaultHeight = 100;
static CalculatorManger * instance = nil;
@implementation CalculatorManger
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (instance == nil) {
instance = [super allocWithZone:zone];
}
});
return instance;;
}
+ (instancetype)sharedManager {
return [[self alloc] init];
}
//方法中定義了一個(gè)block數(shù)據(jù)類型參數(shù)(返回值為int類型的残家,且?guī)в幸粋€(gè)int類型的形參)
- (void)calculate:(int (^)(int))calculateBlock {
//calculateBlock接受外界傳入的代碼塊,也就意味著怎么去操作是由外界調(diào)用者決定的
_result = calculateBlock(defaultHeight);
}
@end
外界控制器調(diào)用
CalculatorManger *manager = [CalculatorManger sharedManager];
[manager calculate:^int(int i) {
NSLog(@"=======i : %d", i);
for (int j = 0; j < 100; j ++) {
i++;
}
return i;
}];
NSLog(@"=====result: %d", manager.result);
可以看到售躁,工具類CalculcatorManager的計(jì)算方法calculate:^int(int)calculateBlock其具體實(shí)現(xiàn)坞淮,交由了外界的控制器調(diào)用者去決定了。雖然有些許繞陪捷,但只要搞清楚block的作為參數(shù)使用時(shí)的格式回窘,理解起來也很快的,如果先前對(duì)這類型的用法在理解上抱有疑惑的話市袖,希望這個(gè)小例子能幫到您:)
5. 匿名Block
Block實(shí)現(xiàn)時(shí)啡直,如上文的局部變量和實(shí)參,等號(hào)右邊就是一個(gè)匿名Block苍碟,它沒有blockName:
^return_type (var_type varName)
{
//...
};
6. typedef Block
利用typedef簡(jiǎn)化Block的聲明
typedef return_type (^BlockTypeName)(var_type);
typedef void (^didQuitAcountBlock)(void);
使用
BlockTypeName aBlock = ^return_type (var_type) {
//...
}
didQuitAcountBlock quitBlock = ^void(void) {
NSLog(@"did quit acount");
};
quitBlock();
7. 內(nèi)聯(lián) Block
這種形式并不常用酒觅,匿名Block聲明后立即被調(diào)用,內(nèi)聯(lián) Block可用于代碼分塊微峰,提高代碼可讀性舷丹,功能類似大括號(hào)的代碼塊,其它功能非常有限
^return_type (var_type varName)
{
//...
}(var);
^void() {
NSLog(@"內(nèi)聯(lián)Block聲明后即被調(diào)用");
}();
8. 遞歸調(diào)用Block
Block內(nèi)部調(diào)用自身蜓肆,遞歸調(diào)用是很多算法基礎(chǔ)颜凯,特別是在無法提前預(yù)知循環(huán)終止條件的情況下。
注意 由于Block內(nèi)部引用了自身仗扬,這里必須使用__block
避免保留環(huán)問題症概。
__block return_type (^blockName)(var_type) = [^return_type (var_type varName)
{
if (returnCondition)
{
blockName = nil;
return;
}
// ...
blockName(varName);
} copy];
blockName(varValue);
實(shí)例
__block int i = 5;
__block void (^ dismisssController)(void) = [^void(void) {
if (i == 0) {
dismisssController = nil;
return;
}
NSLog(@"recursionBlock i = %d", i);
i --;
dismisssController();
} copy];
dismisssController();
8. Block做為返回值
- (return_type(^)(var_type))methodName
{
// ...
}
3. 一個(gè)Block傳參的例子
.h
@interface SecondViewController : UIViewController
@property (nonatomic, copy) void(^ didLoginSuccess)(NSString *username);
@property (nonatomic, copy) void(^ didLoginFailed)(void);
@end
.m
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
if (self.didLoginSuccess) {
self.didLoginSuccess(@"碼代碼的小馬");
}
if (self.didLoginFailed) {
self.didLoginFailed();
}
}
調(diào)用block
SecondViewController *vc = [[SecondViewController alloc] init];
[self.navigationController pushViewController:vc animated:true];
vc.didLoginSuccess = ^(NSString * _Nonnull username) {
NSLog(@"congratulations %@! welcome to objc world", username);
};
vc.didLoginFailed = ^{
NSLog(@"login failed");
};