block和GCD是ios高級程序員面試必問的問題,本篇先介紹下block
第一部分:概述
實體形式如下:
^(傳入參數列){行為主體}
lock實體開頭是“^”,接著是由小括號所包起來的參數列(比如
int a, int b, int c),行為主體由大括號包起來,專有名字叫做block literal。行為主體可以用return回傳值,類型會被compiler自動辨別。如果沒有參數列要寫成:
^(void)。
第二部分:具體用法
一:block的初級用法
/*test 1 使用^運算子來宣告一個block變數*/ int multiplier = 7; int (^myblock)(int) = ^(int num){ return num*multiplier; }; printf("%d\n",myblock(5)); /*test 2 在需要使用block的地方直接用內嵌的方式將block的內容寫出來*/ char * myCharacters[3] = {"TomJohn","George","Charles Condomine"}; qsort_b(myCharacters, 3, sizeof(char*), ^(const void*l,const void*r)//排序函數,個人感覺sort快速排序很好用 { char*left = *(char**)l; char*right= *(char**)r; return strncmp(left, right, 1); } ); printf("%s\n",myCharacters[0]); /*test 3 在block內修改變量*/ __block int multiplier2 = 7; int(^myblock2)(int) = ^(int num){ if (num>5) { multiplier2 = 0; }else{ multiplier2 = 3; } return multiplier2; }; NSLog(@"%d,%d\n",myblock2(8),myblock2(3));
二:定義一個block
可以參考,對照block的實體形式
/*回傳void,參數也是void的block*/ void(^blockReturningVoidWithVoidArgument)(void); /*回傳整數,兩個參數分別是整數和字元形態的block*/ int (^blockReturningIntWithIntAndCharArguments)(int,char); /*回傳void,含有10個block的陣列,每個block都有一個形態為整數的參數*/ void(^arrayofTenBlockReturningVoidWinIntArgument[10])(int);
/*test 1 區域變數的使用方式*/ // 加上__block 修飾詞變量才能在block中修改操作 int x = 123; void (^printXAndY)(int) = ^(int y){ printf("%d,%d\n",x,y); }; printXAndY(20); // 加上__block 修飾詞變量才能在block中操作 /*test 2 各個類型的變數和block之間的互動*/ NSInteger localCounter = 42; __block char localCharacter; void (^aBlock)(void) = ^(void) { // ++CounterGlobal;//可以存取 ++CounterStatic;//可以存取 // CounterGlobal = localCounter; localCharacter = 'a'; }; ++localCounter; localCharacter = 'b'; aBlock(); printf("test2:%ld,%ld,%c\n",localCounter,CounterStatic,localCharacter);四:使用block
/*test 1 當block宣告成一個變數時,我們可以像使用一般函數的方式來使用它*/ int (^twoFrom)(int) = ^(int anInt){ return anInt-1; }; printf("1 from 10 is %d\n",twoFrom(10)); float (^distanceTraveled)(float,float,float) = ^(float startingSpeed,float acceleration,float time){ float distance = (startingSpeed*time)+(0.5*acceleration*time*time); return distance; }; printf("howFar %f\n",distanceTraveled(0.0,9.8,1.0)); /*test 2 一般情況下若是將block當做是參數傳入函數,我們通常會使用內嵌的方式來使用block*/ char*myCharacter_s[3] = {"TomJohn","George","Charles Condomine"}; qsort_b(myCharacter_s, 3, sizeof(char*), ^(const void*l,const void*r){ char*left = *(char**)l; char*right = *(char**)r; return strncmp(left, right, 1); }); /*test 3 在上邊的例子中,block本身就是函數參數的一部分,在下一個例子中dispatch——apply函數中使用block,dispatch_apply的定義如下*/ // void dispatch_apply(size_t iterations,dispatch_queue_t queue,void(^block)(size_t)); size_t count = 12; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(count, queue, ^(size_t i){//類似於for循環 printf("%zu\n",i*2); }); /*test 4 SDK中提供了很多使用block的方法,我們可以像傳遞一般參數的方式來傳遞block,下面這個范例示范如何在一個陣列的前五筆資料中取出我們想要的資料的索引值*/ //所有的資料 NSArray*array = [NSArray arrayWithObjects:@"A",@"B",@"C",@"A",@"B",@"Z",@"G",@"are",@"Q", nil]; //我們只要這個集合內的資料 NSSet*filterSet = [NSSet setWithObjects:@"A",@"B",@"Z",@"Q", nil]; BOOL(^test)(id obj,NSUInteger idx,BOOL*stop); test = ^(id obj,NSUInteger idx,BOOL *stop){ if (idx<5) { if ([filterSet containsObject:obj]) { return YES; } } return NO; }; NSIndexSet*indexes = [array indexesOfObjectsPassingTest:test]; NSLog(@"indexes:%@",indexes);