Block究竟有哪些稱呼和官方的解釋。
匿名函數(shù),塊函數(shù),塊,block基本上他們都是同一個鳥人。
維基百科中說,Block是Apple Inc.為C,C++,以及OC 添加的新特性,使得它們可以用lambda表達式的語法來創(chuàng)建閉包.(lambda表達式既匿名函數(shù)表達式,閉包既是可以包含自由(未綁定到特定對象)變量的代碼塊,具體可以自己下去認真理解下)。我理解為block就是用匿名函數(shù)表達式創(chuàng)建的代碼塊.
閉包就是能夠讀取其它函數(shù)內(nèi)部變量的函數(shù)
什么時候使用block.
Block除了能夠定義參數(shù)列表、返回類型外,還能夠獲取被定義時的詞法范圍內(nèi)的狀態(tài)(比如局部變量),并且在一定條件下(比如使用__block變量)能夠修改這些狀態(tài)。此外,這些可修改的狀態(tài)在相同詞法范圍內(nèi)的多個block之間是共享的,即便出了該詞法范圍(比如棧展開,出了作用域),仍可以繼續(xù)共享或者修改這些狀態(tài)。通常來說,block都是一些簡短代碼片段的封裝,適用作工作單元,通常用來做并發(fā)任務、遍歷、以及回調(diào)。
block如何聲明
[轉(zhuǎn)載]iOS中block實際應用初探
int (*CFunc)(int a) 函數(shù)調(diào)用 int result = CFunc(10);
int (^BFunc)(int a) 函數(shù)調(diào)用 int result = BFunc(10);
block用法1
void (^myblocks) (void) = NULL;
myblocks = ^(void) {
NSLog(@"in blocks");
};
NSLog(@"before myblocks");
myblocks();
NSLog(@"after myblocks");
int (^myblocks2) (int a, int b) = ^(int a, int b) {
int c = a + b;
return c;
};
NSLog(@"before blocks2");
int ret = myblocks2(10, 20);
NSLog(@"after blocks2 ret %d", ret);
//此處如果不加__block會報錯
__block int sum = 0;
int (^myblocks3) (int a, int b) = ^(int a, int b) {
sum = a + b;
return 3;
};
myblocks3(20, 30);
NSLog(@"sum is %d", sum);
對于這種用法,本人不才,基本沒有在實際項目中用過.因為我的理解這實際意義不大(如果是這種簡單的計算),唯一作用是提高程序的并發(fā)性.
回調(diào)是block一個重要的特性.
block回調(diào)是我在網(wǎng)絡請求中用得最多的.
這里先用前輩在ASIHTTP中的block為例子.
定義block
#if NS_BLOCKS_AVAILABLE
typedef void (^ASIBasicBlock)(void);
typedef void (^ASIHeadersBlock)(NSDictionary *responseHeaders);
typedef void (^ASISizeBlock)(long long size);
typedef void (^ASIProgressBlock)(unsigned long long size, unsigned long long total);
typedef void (^ASIDataBlock)(NSData *data);
#endif
此定義可以是全局的block,
這里只用了上門定義的其中一個block為例,作為ASIHTTPRequest的一個屬性.(意思是block可以作為一個對象的屬性存在)
@interface ASIHTTPRequest : NSOperation {
ASIBasicBlock completionBlock;
}
//向外暴露一個接口? 這里是為回調(diào)留一接口方法,其實也可以不用留
- (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock;
方法實現(xiàn)(這里用release是為開啟arc)
@implementation ASIHTTPRequest
- (void)setCompletionBlock:(ASIBasicBlock)aCompletionBlock
{
[completionBlock release];
completionBlock = [aCompletionBlock copy];
}
這里是網(wǎng)絡請求完成后的方法,在這里實現(xiàn)我們block的調(diào)用.
- (void)reportFinished
{
#if NS_BLOCKS_AVAILABLE
if(completionBlock){
completionBlock();
}
#endif
}
@end
如下,然后你可以在你請求網(wǎng)絡的類實現(xiàn)中,實現(xiàn)網(wǎng)絡請求并獲取網(wǎng)絡請求成功后的回調(diào), 這里可以回傳參數(shù)變量(我們這個例子block是回傳的參數(shù)為void,--typedef void (^ASIBasicBlock)(void)--).在這里回傳參數(shù)就是,上面說的參數(shù)共享,就象遍歷數(shù)組,這樣也許你更能理解
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
}];
這里的obj 和idx 以及stop都可以為你在回調(diào)時候所用,就好比代理delegate回傳參數(shù)一樣.
ASIHTTPRequest *request = [self requestWithUrl:url];
//請求成功
[request setCompletionBlock:^{
switch (request.responseStatusCode) {
case RequestStatus_OK:
complete(request.responseString);break;
case RequestStatus_ErrorRequest:
failed(@"錯誤的請求");break;
case RequestStatus_NotFound:
failed(@"找不到指定的資源");break;
case RequestStatus_Error:
failed(@"內(nèi)部服務器錯誤");break;
default:
failed(@"服務器出錯");break;
}
}];
//請求失敗
[request setFailedBlock:^{
failed(@"網(wǎng)絡連接失敗");
}];
這里的FailedBlock我們沒有舉例實現(xiàn).
看了前輩的block實現(xiàn),兄弟伙寫是否有所理解?接下來看看,我寫的一個block的簡單用法.
第一種,接網(wǎng)絡請求的block自己再次封裝的方法.把block作為方法參數(shù)使用.
@interface JHttpRequest : NSObject
//異步Get請求
+ (ASIHTTPRequest *)asyncGetRequest:(NSString *)url complete:(void (^)(NSString *responseStr))complete failed:(void (^)(NSString *errorMsg))failed;
//異步Get請求帶緩存
//異步Post請求
//異步Post上傳圖片
//異步下載請求
//生成異步請求對象
@end
//發(fā)送異步Get請求
+ (ASIHTTPRequest *)asyncGetRequest:(NSString *)url
complete:(void (^)(NSString *responseStr))complete
failed:(void (^)(NSString *errorMsg))failed{
ASIHTTPRequest *request = [self requestWithUrl:url];
[request setUserAgent:UserAgent];
[request setTimeOutSeconds:5.];
//請求成功
[request setCompletionBlock:^{
switch (request.responseStatusCode) {
case RequestStatus_OK:
complete(request.responseString);break;
case RequestStatus_ErrorRequest:
failed(@"錯誤的請求");break;
case RequestStatus_NotFound:
failed(@"找不到指定的資源");break;
case RequestStatus_Error:
failed(@"內(nèi)部服務器錯誤");break;
default:
failed(@"服務器出錯");break;
}
}];
//請求失敗
[request setFailedBlock:^{
failed(@"網(wǎng)絡連接失敗");
}];
//開始請求
[request startAsynchronous];
return request;
}
下面是你需要調(diào)用網(wǎng)絡接口的viewcontroller種對上面網(wǎng)絡請求block方法的調(diào)用
[JHttpRequest asyncGetRequest:url complete:^(NSString *responseStr) {
if (responseStr) {
NSDictionary *getDic = [responseStr JSONValue];
if ([[getDic objectForKey:@"success"] boolValue]) {
//getDic 請求成功取得的json數(shù)據(jù)
}else{
faild([getDic objectForKey:@"msg"]);
}
}else{
faild(@"獲取信息失敗");
}
} failed:^(NSString *errorMsg) {
faild(errorMsg);
}];
綜上例子所訴,block可以作為一個方法參數(shù)使用,能更方便地去取得回調(diào)數(shù)據(jù).
第二種,把block作為類的屬性來使用.
//定義一個block作為viewcontroler的一個屬性.
@interface FirstViewController : UIViewController{
//定義一個blocks變量
void (^BarkCallback) (FirstViewController *thisDog, int count);
NSInteger barkCount;
}
@property(nonatomic , copy) void (^BarkCallback) (FirstViewController *thisDog, int count);
@end
其中void (^BarkCallback) (FirstViewController *thisDog, int count);thisDog count是參數(shù).
@implementation FirstViewController
@synthesize BarkCallback;
- (void)viewDidLoad
{
[super viewDidLoad];
barkCount = 0;
//這里我們啟動一個定時器方便回調(diào)看效果
[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];
}
-(void) updateTimer:(id) arg
{
barkCount ++;
if (BarkCallback) {
//調(diào)用從其他類傳過來的BarkCallback
BarkCallback(self, barkCount);
}
}
@end
實現(xiàn)block
FirstViewController *viewController = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil];
viewController.BarkCallback = ^(FirstViewController *thisDog, int count) {
NSLog(@"count == %d", count);
};
把block作為類的屬性來使用.還有一種表達方法.
typedef void (^BarkCallback) (FirstViewController *thisDog, int count);
@interface FirstViewController : UIViewController{
NSInteger barkCount;
}
@property (nonatomic, copy) BarkCallback completionHandler;
@end
@implementation FirstViewController
@synthesize completionHandler;
- (void)viewDidLoad
{
[super viewDidLoad];
barkCount = 0;
[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES];
}
-(void) updateTimer:(id) arg
{
barkCount ++;
if (completionHandler) {
completionHandler(self, barkCount);
}
}
@end
實現(xiàn)block
FirstViewController *viewController = [[FirstViewController alloc]initWithNibName:@"FirstViewController" bundle:nil];
BarkCallback myab = ^(FirstViewController *thisDog, int count) {
NSLog(@"count == %d", count);
};
viewController.completionHandler = myab;
把block作為全局變量來使用.(無意間奇葩地自己創(chuàng)造出來的)
void (^ BarkCallback) (FirstViewController *thisDog, int count);
@interface FirstViewController : UIViewController{
NSInteger barkCount;
}
@end
@implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
barkCount = 0;
[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];
}
-(void) updateTimer:(id) arg
{
barkCount++;
if (BarkCallback) {
BarkCallback(self, barkCount);
}
}
@end
實現(xiàn)block
#import "FirstViewController.h"
BarkCallback? = ^(FirstViewController *thisDog, int count) {
NSLog(@"person do 1 222count %d", count);
};
最后,把block方法的參數(shù)來使用.(上面已經(jīng)提到過)
@interface FirstViewController : UIViewController{
}
//向外暴露一個接口
-(void) setBark:( void (^) (FirstViewController *thisDog, int count) ) eachBark;
@end
@implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
barkCount = 0;
[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];
}
-(void) updateTimer:(id) arg
{
barkCount++;
}
-(void) setBark:(void (^)(FirstViewController *, int))eachBark
{
eachBark(self, barkCount);
//在這里我們直接把block回調(diào)了,其實一般不這樣直接回調(diào),一般情況是在某種動作完成后回調(diào),比如網(wǎng)絡請求,比如用戶動作監(jiān)聽到以后回調(diào),所以在這里我們可以簡單改進下.
}
@end
方法改進
@interface FirstViewController : UIViewController{
//多定義個block變量指針
void (^BarkCallback) (FirstViewController *thisDog, int count);
}
//向外暴露一個接口
-(void) setBark:( void (^) (FirstViewController *thisDog, int count) ) eachBark;
@end
@implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
barkCount = 0;
[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(updateTimer:)userInfo:nil repeats:YES];
}
-(void) updateTimer:(id) arg
{
barkCount++;
//在動作完成,或者監(jiān)聽到用戶操作時,調(diào)用這個block。這里我們是用timer定時調(diào)用.
if (BarkCallback) {
BarkCallback(self, barkCount);
}
}
-(void) setBark:(void (^)(FirstViewController *, int))eachBark
{
//把實現(xiàn)類傳過來的block指針付值給,我們定義的BarkCallback
BarkCallback = [eachBark copy];
}
@end