block基础

在ios,blocks是对象,它封装了一段代码,这段代码可以在任何时候执行。

Blocks可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。

它和传统的函数指针很类似,但是有区别:

blocks是inline的,并且它对局部变量是只读的。


Block是C级别的语法和运行时特性。

Block比较类似C函数,但是Block比之C函数,其灵活性体现在栈内存、堆内存的引用,我们甚至可以将一个Block作为参数传给其他的函数或者Block。


Blocks的定义:

     int (^myBlock) (int a,int b) = ^(int a,int b){  
       return a+b;  
   };  


定义了一个名为myBlock的blocks对象,它带有两个int参数,返回int。等式右边就是blocks的具体实现。

为了性能,默认Block都是分配在stack上面的,所以它的作用区域就是当前函数。

只要没对Block进行copy操作,它一直存在stack里面。一旦进行了block的copy操作,

block就会放在堆里面。

以下是block基础的简单示例:



void (^BoolBlock)(BOOL);


typedef void (^BoolBlock)(BOOL);

//一个只接受一个BOOL参数,没有返回值的block

typedef int (^IntBlock)(void);

//一个没有参数,返回intblock

typedef BoolBlock (^HugeBlock)(IntBlock);

//看看,这个HugeBlock的参数和返回值都是block



#import <Foundation/Foundation.h>


int main(int argc,constchar * argv[])

{


    @autoreleasepool {

        

// 简单示例

        

        //block的使用范围

        int i =1024;

        void (^blk)(void) = ^ {

            printf("%d\n", i);

        };

        blk();

        

        //block的简单定义

        int (^blockPlus)(int a,int b) = ^(int a,int b){

            return a+b;

        };

        int C = blockPlus(3,5);

        NSLog(@"%d",C);

        

        //block改变外部变量

        int outA =8;

        int (^myPtr)(int) = ^(int a){return outA + a;};//block里面可以读取同一类型的outA的值

        outA = 5//在调用myPtr之前改变outA的值

        int result = myPtr(3); // result的值仍然是11,并不是8

        NSLog(@"result=%d", result);

        //为什么result的值仍然是11?而不是8呢?事实上,myPtr在其主体中用到的outA这个变量值的时候做了一个copy的动作,把outA的值copy下来,存出道另外一个位置。所以,之后outA即使换成了新的值,对于myPtr里面copy的值是没有影响的。

        //需要注意的是,这里copy的值是变量的值,如果它是一个记忆体的位置(地址),换句话说,就是这个变量是个指针的话,它的值是可以在block里被改变的。

        

//block 的目的是为了支持并行编程,对于普通的 local 变量,我们就不能在 block 里面随意修改(原因很简单,block 可以被多个线程并行运行,会有问题的),而且如果你在 block 中修改普通的 local 变量,编译器也会报错。那么该如何修改外部变量呢?有两种办法,第一种是可以修改 static 全局变量;第二种是可以修改用新关键字 __block 修饰的变量。

        //block改变外部变量

        __block int B =4;

        int (^blockPlusC)(int a,int b) = ^(int a,int b){

            B = blockPlus(B,b);

            NSLog(@"B = %d",B);

            B = blockPlus(a,b);

            return B;

        };

        B = 7;

        NSLog(@"B = %d",B);

        int A = blockPlusC(4,5);

        NSLog(@"A = %d~~B = %d",A,B);


        //block中对static中的值的影响

        staticint outA1 =8;

        int (^myPtr1)(int) = ^(int a){return outA + a;};

        outA1 = 5;

        int result1 = myPtr1(3); //result的值是8,因为outAstatic类型的变量

        NSLog(@"result1 = %d", result1);

        

        //block中对static中的值的修改

        staticint outA22 =8;

        int (^myPtr22)(int) = ^(int a){

            outA22 = 5;

            return outA22 + a;

        };

        int result22 = myPtr22(3); //result的值是8,因为outAstatic类型的变量

        NSLog(@"result22=%d", result22);

        

        //对象的存取

        NSString * str =@"BBB";

        NSString * (^blockString)() = ^(){

            NSString * b =@"aaa";

            return b;

        };

        str = blockString();

        NSLog(@"str3 = %@",str);

        

        //对象的改变

       //需要注意的是,这里copy的值是变量的值,如果它是一个记忆体的位置(地址),换句话说,就是这个变量是个指针的话,它的值是可以在block里被改变的。

如下例子:

        NSMutableArray *mutableArray = [NSMutableArrayarrayWithObjects:@"one",@"two",@"three", nil];

        int resultww = ^(int a){

            [mutableArray addObject:@"four"];

            return a*a;

        }(5);

        NSLog(@"test array :%@ %d", mutableArray,resultww);

        //原本mutableArray的值是{@"one",@"two",@"three"},在block里面被更改mutableArray后,就变成{@"one", @"two"}了。


//但是这种变更是在block截获OC对象变量的值的基础上的。

//在blocks中,block表达式截获所实用的自动变量的值,即保存该自动变量的瞬间值。

//即使改变了block中使用的自动变量的值也不会影响block执行时的自动变量的值。   

//但是,如果想在block语法中将值赋给在block语法外声明的自动变量,需要在该自动变量上附上 __block.

//如果将值赋给block中截获的自动变量(非对象),就会产生编译错误!

//但如果截获的是Objective-C对象,block调用变更该对象的方法是不会有错误的,而向截获的变量赋值则会产生编译错误。

//即如上面最近的代码所示,该block中所截获的变量值为NSMutableArray类的对象。如果用C描述,即是截获的NSMutableArray类对象用的结构体实例指针。虽然赋值给截获的自动变量array的操作会产生编译错误,但使用截获的值却不会有任何问题。



//        生命周期和内存管理

//        

//        因为block也是继承自NSObject,所以其生命周期和内存的管理也就非常之重要。

//        block一开始都是被放到堆里,换句话说其生命周期随着methodfunction结束就会被回收,和一般变量的生命周期一样。

//        关于内存管理请遵循这几点

//        1. block pointer的实现会在methodfunction結束后就会被清理

//        2. 如果要保存block pointer要用- copy指令,这样block pointer就會被放到堆里

//        2.1 block 实现用到的block variable也会被移到到heap而有新的内存地址,且一并更新有用到这个block variableblock都指到新的位置

//        2.2 一般的variable值会被copy

//        2.3 如果主体里用到的variableobject的话,此object会被retain, block release時也会被release

//        2.4 __block variable 里用到的object是不会被retain


    }

    return 0;

}

//        2.4 __block variable 里用到的object是不会被retain


稍做补充:

1,Block是Objective C语言中的对象 。

2,Block对象与一般的类实例对象有所不同,一个主要的区别就是分配的位置不同,block默认在栈上分配,一般类的实例对象在堆上分配。


retain是对一个在堆中分配内存的对象的引用计数做了增加,执行release操作的时候检查计数是否为1,如果是则释放堆中内存。

而对于在栈上分配的block对象,这一点显然有所不同,如果方法调用返回,栈帧上的数据自然会作废处理,不像堆上内存,需要单独release,就算NSArray对block对象本身做了retain也无济于事。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值