日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅析OC中的block

發布時間:2024/1/18 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅析OC中的block 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、Block

帶有 自動變量/局部變量 的匿名函數叫做 block ,又叫做 匿名函數代碼塊

完整形式的 Block 語法與一般的 **C語言 **函數定義相比,僅有兩點不同:

  • 沒有函數名 不含函數名是因為其為匿名函數。
  • 帶有 “ ^ ” 返回值類型前帶有 ^ ,由于 OSX,iOS 應用程序中將大量使用 Block 因此插入該記號便于查找。

Block語法

  • 無參無返
//1,無參數,無返回值,聲明和定義void(^MyBlockOne)(void) = ^(void){NSLog(@"無參數,無返回值"); }; MyBlockOne();//block的調用
  • 有參無返
//2,有參數,無返回值,聲明和定義void(^MyblockTwo)(int a) = ^(int a){NSLog(@"@ = %d我就是block,有參數,無返回值",a);}; MyblockTwo(100);
  • 有參有返
//3,有參數,有返回值int(^MyBlockThree)(int,int) = ^(int a,int b){ NSLog(@"%d我就是block,有參數,有返回值",a + b);returna + b; }; MyBlockThree(12,56);
  • 無參無返
//4,無參數,有返回值int(^MyblockFour)(void) = ^{NSLog(@"無參數,有返回值");return45;}; MyblockFour();

我們使用 “{ }” 限定 Block 的范圍,這一點與函數和方法的定義很相似。

類似于使用一個C函數指針, 我們可以聲明一個變量來存儲 Block

void (^simpleBlock)(void); //同樣也可以這樣來為block變量賦值 simpleBlock = ^{NSLog(@"This is a block");};

需要注意的是: Block 賦值和其它類型的變量賦值一樣, 需要以 ; 結尾。

我們也可以在聲明變量的同時為其賦值:

void (^simpleBlock)(void) = ^{NSLog(@"This is a block");}; //之后我們就可以像這樣調用Block了:simpleBlock();

帶有參數和返回值的Block

和函數和方法類似,Block 可以接收參數或者有返回值。

假如我們需要聲明一個兩個 double 類型相乘并返回結果的 Block

double (^multiplyTwoValues)(double, double); //對應的 block 實現如下^ (double firstValue, double secondValue) {return firstValue * secondValue;} //在這個例子中, 返回值可以通過return 表達式推斷出來. 當然我們也可以像這樣顯式聲明返回值類型:^ double (double firstValue, double secondValue) {return firstValue * secondValue;}

在我們聲明并定義了 Block 之后,我們可以就像調用函數一樣,調用 Block 了:

double (^multiplyTwoValues)(double, double) =^(double firstValue, double secondValue) {return firstValue * secondValue;};double result = multiplyTwoValues(2,4);NSLog(@"The result is %f", result);

Block捕獲上下文信息

Block 不僅僅包含了可執行的代碼片段,Block 也有能力從臨近作用域捕獲上下文信息。

如果我們定義了一個方法內部的 BlockBlock 可以捕獲方法內作用域的上下文信息:

- (void)testMethod {int anInteger = 42;void (^testBlock)(void) = ^{NSLog(@"Integer is: %i", anInteger);};testBlock(); }

在這個例子中,anIntegerblock 外部聲明,但是在 block 定義時, 它的值被 block “捕獲” 了。

這里捕獲的僅僅是值, 當我們在 block,的定義和 block 的調用之間修改 anInteger 的值時:

int anInteger = 42;void (^testBlock)(void) = ^{NSLog(@"Integer is: %i", anInteger);};anInteger = 84;testBlock();

testBlock( ) 的輸出并不會被 anInteger 的新值影響,因為我們只捕獲了值,因此輸出如下:

Integer is: 42

這也意味著 Block 不能改變捕獲變量的原值。

__block的使用

如果我們需要從 block 內部改變外部捕獲變量的值時, 我們可以在要修改的外部變量聲明中使用 __block 存儲類型修飾符。使用了 __block 修飾符的變量的儲存空間,被它本身的作用域與引用了它的 __block 的作用域所共享:

__block int anInteger = 42;void (^testBlock)(void) = ^{NSLog(@"Integer is: %i", anInteger);};anInteger = 84;testBlock();

由于使用了**__block** 修飾 anInteger ,因此 anInteger 的存儲和 block 的聲明共享。因此輸出如下:

Integer is: 84

這也意味著在 Block 中可以修改原值:

__block int anInteger = 42;void (^testBlock)(void) = ^{NSLog(@"Integer is: %i", anInteger);anInteger = 100;};testBlock();NSLog(@"Value of original variable is now: %i", anInteger);

此時輸出如下:

Integer is: 42Value of original variable is now: 100

函數指針和指針函數

block 本質上是一個函數指針。

指針函數與函數指針表示方法的不同,不要混淆。最簡單的辨別方式就是看函數名前面的指針 * 號有沒有被括號( )包含,如果被包含就是函數指針,反之則是指針函數

主要的區別是一個是指針變量,一個是函數

1.指針函數

帶指針的函數,即本質是一個函數。函數返回類型是某一類型的指針。

**類型標識符 函數名(參數表) int f(x,y);

首先它是一個函數,只不過這個函數的返回值是一個地址值。指針函數一定有函數返回值,而且在主調函數中,函數返回值必須賦給同類型的指針變量。

float *fun(); float *p; p = fun( );

當一個函數聲明其返回值為一個指針時,實際上就是返回一個地址給調用函數,以用于需要指針或地址的表達式中。由于返回的是一個地址,所以類型說明符一般都是 int

int *f(int a, int b); //上面的函數聲明又可以寫成如下形式:int* f(int a, int b); //讓指針標志 * 與int緊貼在一起,而與函數名f間隔開,這樣看起來就明了些了,f是函數名,返回值類型是一個int類型的指針。 int *f(int a, int b); // 聲明指針函數 int main(int argc, char* argv[]) {printf("------------------------------ Start\n");int *p1 = NULL;printf("The memeory address of p1 = 0x%x \n", p1);p1 = f(1, 2);printf("The memeory address of p1 = 0x%x \n", p1);printf("*p1 = %d \n", *p1);printf("------------------------------ End\n");getchar();return 0; }/*指針函數的定義,返回值是指針類型int */ int *f(int a, int b) { int *p = (int *)malloc(sizeof(int)); printf("The memeory address of p = 0x%x \n", p); memset(p, 0, sizeof(int)); *p = a + b; printf("*p = %d \n", *p);return p; } ------------------------------ 開始 The memeory address of p1 = 0x0 The memeory address of p = 0x551ed0 *p = 3 The memeory address of p1 = 0x551ed0 *p1 = 3 ------------------------------ 結束

通過運行結果,可以看出,指針函數 f 返回的類型是一個指針類型,因為 f 是賦值給 int 類型指針 p1 的,如果不是指針類型,編譯就會出錯。

所以,指針函數就是返回一個地址給調用者,用于需要地址的情況。

2.函數指針(Block)

指向函數(首地址)的指針變量,即本質是一個指針變量。

函數指針說的就是一個指針,但這個指針指向的函數,不是普通的基本數據類型或者類對象。

指向函數的指針包含了函數的地址,可以通過它來調用函數。

*聲明格式:類型說明符 (函數名) (參數)

其實這里不能稱為函數名,應該叫做**指針的變量名。這個特殊的指針指向一個返回整型值的函數**。指針的聲明必須和它指向函數的聲明保持一致。指針名和指針運算符外面的括號改變了默認的運算符優先級。如果沒有圓括號,就變成了一個返回整型指針的函數的原型聲明。

int (*f)(int a, int b); // 聲明函數指針

當然,函數指針的返回值也可以是指針。上面的函數指針定義為一個指向一個返回值為整型,有兩個參數并且兩個參數的類型都是整型的函數。

下面是利用函數指針分別求兩個整數的最大值和最小值的用法:

/* 求最大值,返回值是int類型,返回兩個整數中較大的一個*/ int max(int a, int b) { return a > b ? a : b; } /* 求最小值,返回值是int類型,返回兩個整數中較小的一個*/ int min(int a, int b) { return a < b ? a : b; }int(*f)(int, int); // 聲明函數指針,指向返回值類型為int,有兩個參數類型都是int的函數int main(int argc, _TCHAR* argv[]) { printf("------------------------------ Start\n");f = max; // 函數指針f指向求最大值的函數max(將max函數的首地址賦給指針f) int c = (*f)(1, 2);printf("The max value is %d \n", c);f = min; // 函數指針f指向求最小值的函數min(將min函數的首地址賦給指針f) c = (*f)(1, 2);printf("The min value is %d \n", c);printf("------------------------------ End\n"); getchar(); return 0; }/* 求最大值,返回值是int類型,返回兩個整數中較大的一個*/ int max(int a, int b) { return a > b ? a : b; } /* 求最小值,返回值是int類型,返回兩個整數中較小的一個*/ int min(int a, int b) { return a < b ? a : b; }int(*f)(int, int); // 聲明函數指針,指向返回值類型為int,有兩個參數類型都是int的函數int main(int argc, _TCHAR* argv[]) { printf("------------------------------ Start\n");f = max; // 函數指針f指向求最大值的函數max(將max函數的首地址賦給指針f) int c = (*f)(1, 2);printf("The max value is %d \n", c);f = min; // 函數指針f指向求最小值的函數min(將min函數的首地址賦給指針f) c = (*f)(1, 2);printf("The min value is %d \n", c);printf("------------------------------ End\n"); getchar(); return 0; } ------------------------------ Start The max value is 2 The min value is 1 ------------------------------ End

例如:

void (*fptr)();

把函數的地址賦值給函數指針,可以采用下面兩種形式:

fptr=&Function; fptr=Function;

取地址運算符 & 不是必需的,因為單單一個函數標識符就標號表示了它的地址,如果是函數調用,還必須包含一個圓括號括起來的參數表。

可以采用如下兩種方式來通過指針調用函數:

x=(*fptr)(); x=fptr();

第二種格式看上去和函數調用無異。但是有些程序員傾向于使用第一種格式,因為它明確指出是通過指針而非函數名來調用函數的。下面舉一個例子:

void (*funcp)(); void FileFunc(), EditFunc(); int main() { funcp = FileFunc; (*funcp)(); funcp = EditFunc; (*funcp)(); } void FileFunc() { printf("FileFunc\n"); }void EditFunc() { printf("EditFunc\n"); }//程序輸出結果為: /*FileFunc EditFunc*/

總結

以上是生活随笔為你收集整理的浅析OC中的block的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。