今天來給大家簡單講解一下block的用法,在講解block之前,我們先來了解一下閉包的概念
1.閉包的概念
我們先來看一下腳本語言的閉包
function funA(callback){
alert(callback());
}
function funB(){
var str = "Hello World"; // 函數funB的局部變量,函數funA的非局部變量
funA(
function(){
return str;
}
);
}
對腳本語言不是很熟悉的同學就很疑惑,這是什麼?感覺文法不通的樣子
其實,網上對閉包的解釋大多都很狹隘,我覺得最經典的還是維基百科給出的解釋。
在計算機科學中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,是引用了自由變量的函數。這個被引用的自由變量将和這個函數一同存在,即使已經離開了創造它的環境也不例外。是以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。
Peter J. Landin 在1964年将術語閉包定義為一種包含環境成分和控制成分的實體。
通俗來講,就是閉包允許函數作為一個參數傳遞給一個函數,或者是作為一個變量傳遞給另一個變量
我們再來看一下C語言中的例子
#include <stdio.h>
#include <stdlib.h>
int main()
{
int max(int,int);
int (*p)(int,int);
int a,b,c;
p = max;
scanf("%d,%d",&a,&b);
c = (*p)(a,b);
printf("a=%d,b=%d,max=%d\n",a,b,c);
return 0;
}
int max(int x,int y)
{
int z;
if(x>y) z = x;
else z = y;
return(z);
}
是不是超級眼熟呢,有同學就問了,什麼鬼?這不就是指向函數的指針麼?
其實說白了,閉包就是指向函數的指針,然後用指針去通路這個函數。其實語言在很多方面都是相通的,大家不要去糾結,如果一個概念你不能了解,但你仍然能夠很好地使用它,那就不用去了解,隻要知道如何使用就好了。就像我們不用了解電腦的内部構造,我們隻要能夠很好地使用電腦完成我們的工作就夠了。
如果大家能夠認識到閉包就是指向函數的指針,那下面就很好了解了
2.Block的基本文法
Block從本質上來說就是Object-C對閉包的實作
我們看一下Block的原型
void ( ^myBlock )( ) = ^(){ };
其實和函數的指針差不了多少,我們用一張圖來詳細解釋一下
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyN5cDNyMjMxEjNxEDM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
注意:這裡隻是對Block的聲明與實作,可以再代碼的任意地方,在進行調用之前,這裡面的代碼不會執行,而且外部的參數也不能在裡面修改
什麼意思呢?比如說:
int number = 10;
// = 右邊的實作部分,無需寫上傳回值類型
int (^sumBlock)(int, int) = ^(int a, int b) {
number = 15; //在這裡number是無法被修改的
return a + b;
};
如果我們要修改怎麼辦?在聲明變量的時候加上 __block (兩個下劃線)就可以了
// 告訴編譯器,number 可能要在block中進行使用
int __block number = 10;
基本文法我們已經知道了,下面我們就來進行一個小小的實戰
3.Block的使用
場景:有一個母親和保姆,在母親外出的時候,需要保姆照顧嬰兒
1>建立一個保姆類
Nanny .h
#import <Foundation/Foundation.h>
@interface Nanny : NSObject
- (void)lookAfterBaby;
@end
Nanny .m
#import "Nanny.h"
@implementation Nanny
- (void)lookAfterBaby
{
NSLog(@"照看Baby");
}
@end
2>建立Mother類
Mother.h
#import <Foundation/Foundation.h>
// block的聲明 和 調用是寫在主動方所在的類
@interface Mother : NSObject
// block 屬性的寫法
// @property (nonatomic, copy) 傳回值類型 (^Block名稱)(形參表);
@property NSString *name;
@property (nonatomic, copy) void (^actionBlock)();
// block 作為方法形參的寫法
// 方法名:(block類型)block名稱
- (void)goOutsideWithAction:(void (^)())action;
@end
Mother.m
#import "Mother.h"
@implementation Mother
- (void)goOutsideWithAction:(void (^)())action
{
NSLog(@"mother 要外出");
action();
}
@end
3>在main.m 檔案中調用
Mother *mother = [[Mother alloc] init];
Nanny *Nanny = [[Nanny alloc] init];
// block可以把緊密關聯的事件邏輯,放在一起
// block可以極大的降低耦合度
[mother goOutsideWithAction:^{
[Nanny lookAfterBaby];
}];
總結:
1.Block 就是Object-C對閉包的實作,在java中就是匿名類,在C語言中就是指向函數的指針
2.Block 的原型就是把指向函數的指針中的 * 修改為 ^ 就可以了
3.Block 隻是聲明和實作了函數,可以存在代碼的任意地方,如果想要函數執行,需要另外調用
4.在Block 中,預設是不允許修改外部變量,如果需要修改,應在聲明變量的時候加上 __block ,告訴編譯器,變量要在Block中使用