Block

Block

1.什么是Block

- Block是iOS中一种比较特殊的数据类型

 

- Block是苹果官方特别推荐使用的数据类型, 应用场景比较广泛

    + 动画

    + 多线程

    + 集合遍历

    + 网络请求回调

    + 用来保存某一段代码, 可以在恰当的时间再取出来调用

    + 功能类似于函数和方法

2.block的格式

- Block的定义格式

返回值类型 (^block变量名)(形参列表) = ^(形参列表) {

 

};

 

-block最简单形式

 

void (^block名)() = ^{代码块;}

 

例如:

void (^myBlock)() = ^{ NSLog(@"lalala"); };

 

-block带有参数的block的定义和使用

 

void (^block名称)(参数列表)

= ^ (参数列表) { // 代码实现; }

 

例如:

void (^myBlock)(int) = ^(int num){ NSLog(@"num = %i", num); };

 

-带有参数和返回值的block

返回类型 (^block名称)(参数列表)

= ^ (参数列表) { // 代码实现; }

 

例如:

int (^myBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; };

 

-调用Block保存的代码

block变量名(实参);

// 注意: 利用typedefblock起别名, 和指向函数的指针一样, block变量的名称就是别名

函数指针使用

typedef int (*calculate) (int, int);

int main(int argc, const char * argv[]) {
    calculate sumP = sum;
    int res = sumP(10, 20);
    NSLog(@"res = %i", res);
    calculate minusP = minus;
    res = minusP(10, 20);
    NSLog(@"res = %i", res);
    return 0;
}

block和typedef

 block使用

int main(int argc, const char * argv[]) {
    int (^sumBlock) (int, int) = ^(int value1, int value2){
        return value1 + value2;
    };
    int res = sumBlock(10 , 20);
    NSLog(@"res = %i", res);
    
    int (^minusBlock) (int, int) = ^(int value1, int value2){
        return value1 - value2;
    };
    res = minusBlock(10 , 20);
    NSLog(@"res = %i", res);
    return 0;
}

block起别名

 

typedef int (^calculteBlock)(int , int);

int main(int argc, const char * argv[]) {
    calculateBlock sumBlock = ^(int value1, int value2){
        return value1 + value2;
    };
    int res = sumBlock(10, 20);
    NSLog(@"res = %i", res);
    calculateBlock minusBlock = ^(int value1, int value2){
        return value1 - value2;
    };
    res = minusBlock(10, 20);
    NSLog(@"res = %i", res);
    
    return 0;

 

Block应用场景

问题1:block的应用场景是什么?

答:当发现代码的前面和后面都是一样的时候, 这个时候就可以使用block

 

Block注意事项

问题1:怎样访问和修改block外的值?

答: 1.block中可以访问外面的变量

int a = 10;
void (^myBlock)() = ^{
    NSLog(@"a = %i", a);
};
myBlock();

问题2:为什么不可以在block中修改外界变量的值?

答:

  1. 默认情况下, 不可以在block中修改外界变量的值,
  2. 因为block中的变量和外界的变量并不是同一个变量
  3. 如果block中访问到了外界的变量, block会将外界的变量拷贝一份到堆内存中
  4. 因为block中使用的外界变量是copy的, 所以在调用之前修改外界变量的值, 不会影响到block中copy的值

int a = 10;
NSLog(@"&a = %p", &a);
void (^myBlock)() = ^{
    //        a = 50;
    NSLog(@"&a = %p", &a);
    NSLog(@"a = %i", a);
};
a = 20;
myBlock();

 

问题3:__block的应用场景?

答: 如果想在block中修改外界变量的值, 必须在外界变量前面加上__block

__block int a = 10;
NSLog(@"&a = %p", &a);
void (^myBlock)() = ^{
    a = 50;
    NSLog(@"&a = %p", &a);
    NSLog(@"a = %i", a);
};
myBlock();
NSLog(@"a = %i", a);

 

问题4: 为什么不加__block不能在block中修改外界变量的值?

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

int a = 10;
void (^myBlock)() = ^{
    //        a = 10;
    NSLog(@"a = %i", a);
};
myBlock();

 

问题5:block是存储在堆中还是栈中?

答:

  1. 默认情况下block存储在栈中, 如果对block进行一个copy操作, block会转移到堆中
  2. 如果block在栈中, block中访问了外界的对象, 那么不会对对象进行retain操作
  3. 但是如果block在堆中, block中访问了外界的对象, 那么会对外界的对象进行一次retain

 

问题6:怎么对block进行内存管理?

答:

  1. 如果在block中访问了外界的对象, 一定要给对象加上block, 只要加上了block, 哪怕block在堆中, 也不会对外界的对象进行retain
  2. 如果是在ARC开发中就需要在前面加上__weak
    __block Person *p = [[Person alloc] init]; // 1

 

问题7:如何避免block出现循环引用?

答: 1.使用一个用__weak 修饰的值指针保存对象 2.或者使用Block_copy(myBlock)

MRC

__block Person *p = [[Person alloc] init]; // 1

ARC

//Person *p = [[Person alloc] init];
//    __weak Person *weakP = p;

NSLog(@"retainCount = %lu", [p retainCount]);
void (^myBlock)() = ^{
    NSLog(@"p = %@", p); // 2
    //        NSLog(@"p = %p", weakP);
    NSLog(@"block retainCount = %lu", [p retainCount]);
};

Block_copy(myBlock);//将block对象转移到堆中
myBlock();

[p release]; 1

 

posted @ 2015-11-26 15:39  a滴答  阅读(205)  评论(0编辑  收藏  举报