BLOCK 概念及简单用法
适用于 IOS4.0+
block简单介绍
1、block简单定义:用^定义,用;结尾
例:
int (^testBlock)(int a, int b ,...);
void (^testBlock2)(int) = ^(int num){
return num * num;
};
注:block可以使用和本身范围相同的参数
2、内嵌的方式使用block
例:
char *testChar[3] = {"test1", "test2","test3"};
testMethod (testChar,^(int a, int b){
reture testChar[a > b ? a : b ] ;
});
3、block参数说明
block内部只能改变block内部和__block声明的外部参数,对于外部声明的没有用__block修饰的参数,系统编译会报错
例:
__block int temp = 7;
int (^changeTemp)(int) = ^(int num){
return ++temp;
};
若temp参数前的__block去掉,编译时就会报异常
block概要
1、功能简介:具有匿名功能的内嵌函数
注:词法作用域:某个函数两个大括号中间的区块,程序执行时系统会将这个区块放入堆叠记忆体中,区块中声明的变量
拥有带有原型的参数
拥有回传值
可以撷取被定义词法作用域:block变量和其它区域变量是统一层级的参数变量,block的内容可以读取到和他同一层级的其他区域变量
可以选择性修改词法作用域
2、使用时机
用来表示、简化一小段的程式码;
适合用来建立一些同步执行的程序代码,封装一些小型工作或是用来作为某一个工作完成时回传呼叫
新的API会大量使用clock来取代delegate的两个原因:
可以直接在代码中撰写等会要接着执行的程序,直接将代码编程函数的参数传入函数中
可以存取区域变量,不用clock时存取区域变量需要将变量封装成结构才能使用,而block可以很方便的存取区域变量
声明建立block
例:
/* 回传void ,参数也是void 的block*/
void (^blockReturningVoidWithVoidArgument)( void );
/* 回传整数,两个参数分别是整数和字元型态的block*/
int (^blockReturningIntWithIntAndCharArguments)( int , char );
/* 回传void ,含有10 个block 的阵列,每个block 都有一个型态为整数的参数*/
void (^arrayOfTenBlocksReturningVoidWinIntArgument[ 10 ])( int );
/* 定义一个block变量,然后再定义一个block把它指定给block变量 */
int (^oneFrom)( int ); /* 宣告block 变数*/
oneFrom = ^(int anInt){
return anInt = - 1 ;
};
/* 声明一个全局的block */
int GlobalInt = 0 ;
int (^getGlobalInt)( void ) = ^ ( void ) { return GlobalInt ;};
block和变量
1、变量的型态
block中拥有的变量类型
全局变量和静态的区域变量
全局函数
区域变量和由封闭领域传入的参数
函数内用__block 修饰的变量,
汇入常量
方法的实体中,可以使用OC的实体变量
套用到block中的变量的使用:
可以存取全局变量和在同一领域中的变量
可以存取传入block参数
在同一领域的区域变量在block中视为常量
可以存取在同一领域中用__block修饰的变量
在block中声明的区域变量使用方式和平常函数使用区域变量的方式相同
2、__block形态变量
可以给block外部的参数加上修饰词__block使其变成可读写形式
例:各类型的变量和block之间的互动
extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void){
++CounterGlobal;//可存可取
++CounterStatic;//可存可取
CounterGlobal = localCounter;//localCounter在block 创建时就不可变了。
localCharacter = 'a'; //设定外面定义的localCharacter 变数
};
++localCounter;//不会影响的block 中的值。
localCharacter = 'b';
aBlock();//执行block 的内容。
//执行完成后,localCharacter会变成'a'
}
3、物件和__block变量
ARC环境下如果block外部变量没有用__block来修饰,则block块中也会对其进行引用计数,如果用__block修饰过,则不参与
需要额外主意的点:
若直接存取类属性,self的引用计数也会+1
若通过变量存取实体属性的值,则变量的参考计数将被+1
例:
dispatch_async (queue, ^{
// 因为直接存取实体变数instanceVariable ,所以self 的retain count 会加1
doSomethingWithObject (instanceVariable);
});
id localVaribale = instanceVariable;
dispatch_async (queue, ^{
//localVariable 是存取值,所以这时只有localVariable 的retain count 加1
//self 的 return count 并不会增加。
doSomethingWithObject (localVaribale);
});
使用block
1、声明block
int (^oneFrom)(int) = ^(int anInt){
return anInt - 1;
};
printf("1 from 10 is %d", oneFrom(10));
float (^distanceTraveled)(float , float , float) = ^(float startSpeed,float acceleration, float time){
float distance = (startSpeed * time) + (0.5 * acceleration * time * time);
return distance;
};
float howFar = distanceTraveled(0.0,9.8,1.0);
2、将block作为函数的参数: 多数情况下使用block不是直接声明而是直接以内嵌的方式来将block传入
char *myCharacters[3] = {"test1","test2","test3"};
qsort_b(myCharacters, 3, sizeof(char *), ^int(const void *l, const void *r) {
char *left = *(char **)l;
char *right = *(char **)r;
return strncmp(left, right,1);
});
size_t count = 10;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(count, queue, ^(size_t i) {
printf("%zu\n",i);
});
3、将block当做方法的参数
NSArray *array = [NSArray arrayWithObjects:@"A",@"B",@"C",@"D",@"E",@"F" ,nil];
NSSet *filterSet = [NSSet setWithObjects:@"A",@"B",@"D", 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);
4、应该避免的使用方式:block是for循环中的局部变量,因此在使用上必须避免将局部的block指定给外面声明的block
void dontDoThis()
{
void (^blockArray[3])(void); //3个block的阵列
for (int i = 0; i < 3; i++) {
blockArray[i] = ^{ printf("hello,%d\n",i); };
//主意,这个block定义仅在for循环中有效
}
}
void dontDoThisEither()
{
void (^block)(void);
int i = random();
if (i > 1000) {
block = ^{ printf("got i at : %d\n",i);};
//注意:这个block定义仅在if后的两个大括号中有效
}
}