block和GCD是ios高级程序员面试必问的问题,本篇先介绍下block
第一部分:概述
Block是一个C级别的语法以及运行时的一个特性,和标准C中的函数(函数指针)类似,但是其运行需要编译器和运行时支持,从ios4.0开始就很好的支持Block,个人感觉使用block最大的便利就是简化的回调过程,以前使用uiview的动画,进程要控制动画结束后进行相应的处理,ios4.0之后,uiview新增了对block的支持,现在只要使用简单的一个block代码就可以在写动画的代码部分直接添加动画结束后的操作,还有就是在使用notification的时候block也是非常有帮助的,反正多用就对了,block大大提高了代码的效率,
block是一个具有匿名功能的内嵌函数,与函数非常相似,,但是Block比之C函数,其灵活性体现在栈内存、堆内存的引用,我们甚至可以将一个Block作为参数传给其他的函数或者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);
三:block和变量
/*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);
如果雷同纯属巧合