Objective-C——Block的使用

一. Block类型和函数指针的比较

1. 无参无返回值

(1). 先定义一个打印花的函数

void hua()
{
  printf(" {@}\n");
  printf("  |\n");
  printf(" \\|/\n");
  printf("  |\n");
}

(2). 比较

// a. 直接调用函数
      hua();

// b. 定义函数指针
      void (*huaP)();
      huaP = hua;
      huaP();

// c. 无参无返回值的Block运用
      void (^huaB)();
      huaB = ^{
            printf(" {@}\n");
            printf("  |\n");
            printf(" \\|/\n");
            printf("  |\n");
          };
      huaB();
2.有参无返回值

(1). 先定义一个有参函数

void sum(int a,int b)
{
  printf("%d\n",a + b);
}

(2).比较

// a.直接调用
    sum(10, 10);

// b.定义函数指针
    void (*sumP)(int,int);
    sumP = sum;
    sumP(20,78);

// c.有参无返回值的Block运用
    void (^sumB)(int,int);
    sumB = ^(int a,int b){
           printf("%d\n",a + b);
        };
    sumB(12,33);
3.有参有返回值

(1).定义一个函数

int add(int a,int b)
{
  return a + b;
}

(2).比较

// a.直接调用
    NSLog(@"%d", add(11,33));

// b.定义函数指针
    int (*addP)(int,int);
    addP = add;
    NSLog(@"%d", add(22,11));

// c.有参有返回值的Block运用
    int (^addB)(int,int);
    //^int(int a,int b)中的反回值类型int可以省略
    addB = ^(int a,int b){  
      return a + b;
    };
    NSLog(@"%d", addB(20,55));

二. 用typedef给Block声明新类型名

1. 定义函数
double multiply(double a,double b)
{
  return  a * b;
}
2. typedef声明新类型名
// (1).用typedef声明新的函数指针名字
    typedef double (*newMultiply)(double,double);
    newMultiply cheng = multiply;
    NSLog(@"函数指针调用:%f",cheng(10.5,2.0));

// (2).用typedef声明新的Block类型名字
    typedef double (^blockMultiply)(double,double);
    blockMultiply chengB = ^(double a,double b){
      return a * b;
    };
    NSLog(@"调用Block:%f",chengB(5.5,2.0));

三. Block运用场景

当前后都有相同代码的的时候,只有中间的代码不一样时,可以考虑用Block变量

// 1. 用Block变量做函数参数
void look(void (^lookB)()){
  printf("起床\n");
  printf("吃早晨\n");
  lookB();
  printf("吃晚餐\n");
  printf("睡觉\n");
}

// 2. 定义Block变量
    void (^lookB)() = ^{
       printf("工作\n");
    };

// 3. 把定义好的Block传入函数
    look(lookB);

四. Block代码块里面的变量和代码块外面的变量交互

1. BlocK里面的代码,可以使用外面的变量值
   int k = 10;
    void (^block1)() = ^{
      NSLog(@"%d",k);
    };
    block1();
2. BlocK里面的代码,不可以直接修改Block外面的变量,因为外面传进来的值是属于值传递,地址不一样。
    void (^block2)() = ^{
      //k = 90;会报错。
      NSLog(@"%d",k);
    };
    block2();
3. 在Block里面要修改Block外面的变量值,外面的变量声明时要加上__block

如果加上__block之后就是地址传递, 所以可以在block中修改外界变量的值

    __block int a = 80;
    printf("%p\n",&a);
    void (^block3)() = ^{
      a = 100;
      NSLog(@"%d",a);
      printf("%p\n",&a);
    };
    block3();

五. 在Block里面使用对象

1. 当在Block里面使用对象,在复制Block变量时,对象引用计时器加1
    Person *person = [Person new];
    NSLog(@"对象没有使用__block %ld",person.retainCount);
    void (^perB)() = ^{
      person.k = 100;
      NSLog(@"对象没有使用__block %ld",person.retainCount);
    };
    Block_copy(perB);
    perB();
2. 当对象使用__block声明,在Block里面使用对象,在复制Block变量时,对象引用计时器不加1
    __block Person *person1 = [Person new];
    NSLog(@"对象使用__block %ld",person1.retainCount);
    void (^perB1)() = ^{
      person1.k = 100;
      NSLog(@"对象使用__block %ld",person1.retainCount);
    };
    Block_copy(perB1);
    perB1();

六. 面试题:block是存储在堆中还是栈中?

  1. 默认情况下block存储在栈中, 如果对block进行一个copy操作, block会转移到堆中。

  2. 如果block在栈中, block中访问了外界的对象, 那么不会对对象进行retain操作。

  3. 但是如果block在堆中, block中访问了外界的对象, 那么会对外界的对象进行一次retain。

  4. 如果在block中访问了外界的对象, 一定要给对象加上__block,只要加上了__block, 哪怕block在堆中, 也不会对外界的对象进行retain。
    如果是在ARC开发中就需要在前面加上__weak。

七. Block代码块的快捷键:inline Block

  <#returnType#>(^<#blockName#>)(<#parameterTypes#>) = ^(<#parameters#>) {
    <#statements#>
  };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值