block变量的概念
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// block 是一个数据类型
// block 和函数非常相似
// 函数不能在另一个函数的内部嵌套,但是block因为不是函数所以说可以在main里面写
// *****************************************************************************************
// 无参的block变量定义
// 书写格式: 返回值类型 (^block变量名) (参数) =^{ 代码块; };
// 调用格式: block变量名();
// 意义:在需要的地方调用
void (^myBlock1)() = ^{
NSLog(@"1234");
};
myBlock1();
void (^blocklalala)(void)=^(void){
NSLog(@"lalala");
};
blocklalala();
// *****************************************************************************************
// 有参的block变量定义
// 书写格式: 返回值类型 (^block变量名) (参数类型列表) =^(形参列表){ 代码块; };
// 调用格式: block变量名(实参列表);
void (^eat)(int ,int )=^(int x,int y){ //a,b表示这个block变量有两个参数,且都是int类型的。而后面的x,y就是类似于函数的形参了
NSLog(@"x+y=%d",x+y);
};
eat(10,10);
void (^wangzhongyao)(int ,int )=^(int a,int b){
NSLog(@"a+b=%d",a+b);
};
wangzhongyao(10,14);
wangzhongyao(1,2);
// *****************************************************************************************
// 带有参数和返回值的block变量定义
int (^blockSum)(int ,int ,int )=^(int a,int b,int c){
return a+b+c;
};
NSLog(@"blockSum=%d",blockSum(1,2,3));
// *****************************************************************************************
// 注意:block变量的返回值可以是其他的block类型
}
return 0;
}
———————————————————————————————————————————
block的typedef用法
事实上,typedef是为block起了一个别名。这和函数指针比较的相似。
注:指针和函数
1)指针函数 (返回值是指针的函数)
2)函数指针 (指向函数的指针)
#import <Foundation/Foundation.h>
int sum(int x,int y)
{
return x+y;
}
void test1()
{//函数指针的回顾
int s=sum(5, 10);
NSLog(@"s=%d",s);
// 定义指向函数的指针
int (*p)(int x,int y);
p=sum;
s=p(3,5);
NSLog(@"s=%d",s);
// 给函数指针起个别名
typedef int (*newType)(int x,int y);//newType 就是一个新类型,而不是函数名
newType p2=sum;//用新的函数指针类型定义一个新的函数指针变量p2,然后用p2指向sum
s=p2(1,2);
NSLog(@"s=%d",s);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
//********************************给无参无返回值的block变量重命名**************************************
// 先建立一个无参无返回值的block
void (^myBlock)()=^{
NSLog(@"这是原来的block!");
};
myBlock();
// 给无参无返回值的block类型起一个别名
typedef void (^newMyBlock)();
// 注意:和指针函数差不多,这里的newMyBlock是一个 新的类型,而不再是block类型的变量名了
newMyBlock f1;//定义一个 无参无返回值的变量f1
f1=^{
NSLog(@"这是通过typedef创建的新类型所定义的block");
};
f1();
//********************************给有参有返回值的block变量重命名**************************************
// 先建立一个有参有返回值的block
int (^sumBlock)(int ,int ,int )=^(int x,int y,int z){
return x+y+z;
};
int sum1=sumBlock(1,2,4);
NSLog(@"sum1=%d",sum1);
// 给有参有返回值的block起一个别名
typedef int (^newTypeForSum)(int ,int ,int );//这里实际上是定义了一个新的类型,而这个新的类型的类型名是newTypeForSum,这个新的类型是一个 返回值是int类型并且有三个int类型的参数的block类型。
newTypeForSum f2;//用新的block类型声明了一个变量f2
f2=^(int x,int y,int z){
return x*y*z;//显然这里可以是对三个参数的任何操作。
};
int s3=f2(3,5,2);
NSLog(@"s3=%d",s3);
// 再写一个block类型,显然我们根本不用先写一个block变量然后再起别名(下面三行代码可以不要),我们可以直接用typedef去写一个新的block类型
// int (^sumBlock1)(int ,int )=^(int x,int y){
// return x+y;
// };
typedef int (^newType1)(int ,int);//直接写了一个返回值是int类型且有两个int类型的参数的新的block类型
newType1 f3;
f3=^(int a,int b){
return a*b;//在新block类型变量内部定义方法
};
int ss=f3(12,12);
NSLog(@"ss=%d",ss);
}
return 0;
}
———————————————————————————————————————————
block访问外部变量
/*
局部变量: 在函数的内部或者代码块的内部定义的变量,都是局部变量
(局部变量存在于内存的栈区)
全局变量: 在函数的外部定义的变量
注意:如果在函数内部定义和全局变量同名的变量,此时在函数内部,局部变量会暂时屏蔽全局变量的作用域
*/
代码:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
int m=100;
__block int m2=111;
void (^myBlock1)(void)=^(void){
// 首先,在block变量的内部可以直接访问其外部的变量
// int m=200;
// 其次,如果在block内部定义了与外部同名的变量,那么就会覆盖外部的变量
// m=300;
// 我们无法直接修改外部的变量,上面一条语句是错误的
m2=222;
// 如果一定要在block变量的内部修改外部的变量值,那么要将外部定义的变量设置为__block类型(注意有两个下划线)
NSLog(@"这是在block变量的内部 m=%d,m2=%d",m,m2);
};
myBlock1();
}
return 0;
}
———————————————————————————————————————————
block应用(1)
日程表,大多数日程计划一致,只有少数不一致时应该怎么使用block
代码:
//用block变量作为函数的参数(可以做到重复输出的时候用block变量只更改需要更改的部分)
#import <Foundation/Foundation.h>
void daysDoThings(void (^dayBlock)())//将 一个无返回值、参数为一个 无返回值无参的block类型 的变量 传进去,这个地方定义传进来的block变量的类型名的时候可以随意
{
printf("--------------- ");
printf("起床");
printf("刷牙");
dayBlock();
printf("吃饭");
printf("睡觉");
printf(" ");
}
void daysDoThings222(int n)
{
typedef void (^newDaysBlock)();//定义一个block变量的新类型
newDaysBlock work;//创建一个newDaysBlock类型的block变量work
switch (n) {
case 1:
work=^{
printf("Day1");
};
break;
case 2:
work=^{
printf("Day2");
};
break;
case 3:
work=^{
printf("Day3");
};
break;
case 4:
work=^{
printf("Day4");
};
break;
default:
break;
}
daysDoThings(work);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 方法①,我们要先创建好这些block类型的变量,然后传入函数进行调用
// void (^dayBlock1)()=^{
// printf("1");
// };
// daysDoThings(dayBlock1);
//
// void (^dayBlock2)()=^{
// printf("2");
// };
// daysDoThings(dayBlock2);
//
// void (^dayBlock3)();
// dayBlock3=^{
// printf("3");
// };
// daysDoThings(dayBlock3);
// 方法②,我们可以直接在调用函数的同时传block变量
//
// daysDoThings(^{
// printf("5");
// });
// 我们可以这样用是因为我们知道,一个block变量是这样定义的:
// void (^myBlock)();
// myBlock=^{ ... };
// 所以可以将block变量的定义部分传进函数里去
// 方法③
daysDoThings222(1);
daysDoThings222(2);
daysDoThings222(3);
daysDoThings222(4);
}
return 0;
}
★附加:用block作为函数的返回值学习完成之后,可以改上面的代码,我现在将改好的代码写在下面,读者学习完毕后可以回来看看。
代码:
#import <Foundation/Foundation.h>
typedef void (^newBlockForDays)();
void days(int day)//记住,block类型的变量名要括号括起来,并且定义block类型的变量的时候要加^
{
newBlockForDays setDays(int i);
//引入setDays方法,不然没法用(函数声明部分)
printf("****");
//创建一个newBlockForDays的变量day1去接收setDays方法的返回值
newBlockForDays day1;
day1=setDays(day);
//day1接收完值后就是一个具备返回值功能的block变量,所以可以直接调用这个block变量
day1();
printf("********** ");
}
newBlockForDays setDays(int i)
//将这个方法改为返回值为block类型变量的方法
{
newBlockForDays workDay;
switch (i) {
case 1:
workDay=^{
printf("Day11111");
};
break;//如果这里不写break,那么默认向下执行,那么workDay的值会一直改变,直到遇到break跳出程序,才终止了对workDay的赋值
case 2:
workDay=^{
printf("Day22222");
};
break;
case 3:
workDay=^{
printf("Day33333");
};
break;
case 4:
workDay=^{
printf("Day44444");
};
break;
case 5:
workDay=^{
printf("Day55555");
};
break;
default:
break;
}
return workDay;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
days(1);
days(2);
days(3);
days(4);
days(5);
}
return 0;
}
———————————————————————————————————————————
block作为函数的返回值
代码:
#import <Foundation/Foundation.h>
//创建一个新的block类型(返回值为int类型,并且含有两个参数)
typedef int (^newBlock1)(int ,int );
//创建一个返回值为newBlock1类型的函数test1 (test函数本身是没有参数的)
newBlock1 test1()
{
//返回值为newBlock1类型,那么自然要先创建一个newBlock1类型的变量用来返回
newBlock1 nb;
//自然变量nb也应该拥有两个int类型的形参
nb=^(int x,int y){
return x>y?x:y;
};
//注意这里返回的是newBlock1类型的变量
return nb;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
newBlock1 n1;
n1=test1();//test1就是返回一个可以判断两个数的较大数的block变量,然后将这个具有这个功能的block变量给n1,这样n1就具备接收参数并判断大小的能力了(可以说每次调用无参函数test1,就生成一个具备相应功能的block类型的变量)
// 这样我们再输出n1(12,11) 此时的n1是接收了参数的n1,返回值为int类型
NSLog(@"n1->max=%d",n1(12,11));
}
return 0;
}
//★上面的程序大家可能不是很理解,我觉得不理解的地方应该是不理解怎么调用的。我着重解释一下:
//首先test1函数是一个返回值为newBlock1类型的无参函数,一定注意test1返回的是一个block类型的变量,而返回的这个block类型的变量是具备以下功能的————接收两个数字并判断两个数字大小,最后返回较大值。
//接着在main函数中先创建一个newBlock1类型的变量n1去接受test1的返回值,这样n1就是一个具备上述功能的block类型的变量了。所以说我们可以给n1传值并输出n1的返回值
//// 对于上面的程序,我们只是为了让block作为函数的返回值而写的,其实完全没有必要这样做,这样做显得非常的麻烦。我们可以直接这么写:
//#import <Foundation/Foundation.h>
//
//int main(int argc, const char * argv[]){
// @autoreleasepool {
// typedef int (^newBlock2)(int x,int y);
// newBlock2 n2;
// n2=^(int x,int y){
// return x>y?x:y;
// };
// NSLog(@"n2->max=%d",n2(12,13));
// }
//}
———————————————————————————————————————————
block的使用技巧及其注意事项
//block和函数的区别:
//①定义方式不一样
//②block是类型,函数就是函数
//③函数不能嵌套定义,block可以嵌套定义
//④block是一中数据类型,所以可以做函数的参数和返回值。函数则不可以(函数不可以做另外函数的参数,也不可以做另外函数的返回值)
#import <Foundation/Foundation.h>
void test(int (^block1)(int num1,int num2))//这里加num1 num2更好,因为这样调用test的时候提示更多
{
}
int main()
{
@autoreleasepool {
test(//test
^int(int num1, int num2) {//注意这里的形式,多了一个int,注意注意注意!!!
void (^myblock)()=^{// 随意嵌套定义的block变量
NSLog(@"QQQQQ");
};
myblock();
return num1+num2;
}
);//test
}
return 0;
}
———————————————————————————————————————————
版权声明:本文为博主原创文章,未经博主允许不得转载。