• BLOCK专题


     

    >>定义并使用一个block    返回值(^名字)(参数列表) =^返回值类型(参数列表){表达式};  其中返回值和参数列表可以神略 ,最简单的block是  ^{xxxx};

     

    void(^add)(int a , int b ) = ^(int a , int b ){

          

            NSLog(@"a+b=%d",a+b);

        };

        

        add(1,3);

     

    >>假设有如下代码

    - (void)viewDidLoad {

        

        int f = 0;

        void(^add)(int a , int b ) = ^(int a , int b ){

            

            NSLog(@"a+b=%d",a+b);

            

            f = 1;

        };

        

        add(1,3);

    }

    这个时候,会提示f=1;这里出现错误,如果需要修改block以外的局部变量(在这个viewDidLoad函数内的)就需要使用 __block int f = 0; 

     

    不需要加入__block就可以直接修改的变量(从下面看出,应该就是变量的生命周期问题)(注释1)

    全局变量

    类的成员变量

    static变量(函数体里面也可以的)

     

    >>有如下代码

    int a = 1;

        

        void(^OutPut)() = ^(){

            

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

        };

        

        a = 2;

        

        OutPut();

     

    上面的代码输出 a=1;

    如果修改为 __block int a = 1;   这样会输出 a=2;(所有的可改变的变量都会输出2,在上面注释1处说明的变量)

     

    >>再看一个例子

    - (void)viewDidLoad {

     

        NSMutableArray * arr = [NSMutableArray arrayWithObject:@"ddd"];

        

        void(^OutPut)() = ^(){

            

            [arr removeLastObject];

            

            arr = [NSMutableArray new];

        };

        

        OutPut();

    }

     

    上面提到比如不加入__block的变量是不能在block里面修改的,这里的arr因为没有加__block 所以在执行 arr = [NSMutableArray new];的时候就出错了,但是[arr removeLastObject];并没有任何问题。

     

     

    >>定义一个 Block Pointer

    上面的 void(^add)(inta,int b) 我们其实可以使用一个typedef来实现

    typedef void(^AddMethod)(int , int );

    AddMethod add = ^(int a , int b ){ NSLog(@“a+b=%d”,a+b};

     

     

    下面涉及到的内容可以看看如下网址

    http://www.cocoachina.com/bbs/read.php?tid=152222

     

    >>NSStackBlock  NSGlobalBlock NSMallocBlock 如何区分(可以通过NSLog来打印出一个block属于哪个类型)

    NSGlobalBlock

    block内不访问任何变量的

    block除了方位全局变量跟static变量的(其中类的成员变量等不在这2种类型里面)

     

    剩下的基本上都是StackBlock

     

    比如:

    void(^outPut)() = ^{

            

            NSLog(@"outPut");

        };

    GlobalBlock,因为block内部没有访问任何变量

     

    比如:

    int a = 0;

        void(^outPut)() = ^{

            NSLog(@"outPut:%d",a);

        };

    StackBlock,因为方位了非(全局,static)变量

     

    比如:

    static int a = 0;

        void(^outPut)() = ^{

            NSLog(@"outPut:%d",a);

        };

    GlobalBlock,因为只访问了static变量

     

    >> 有了上面3个Block存储区域的概念,我们就比较容易理解了下面的内容了。

     

    例子:

    • void exampleB_addBlockToArray(NSMutableArray *array) {
    •   char b = 'B';
    •   [array addObject:^{
    •     printf("%c ", b);
    •   }];
    • }
    •  
    • void exampleB() {
    •   NSMutableArray *array = [NSMutableArray array];
    •   exampleB_addBlockToArray(array);
    •   void (^block)() = [array objectAtIndex:0];
    •   block();
    • }

    首先看addObject这个block是一个StackBlock

    在ARC情况下,执行正确 :因为ARC下会自动将StackBlock拷贝到MallocStack中

    在非ARC情况下,执行错误:因为在exampleB_addBlockToArray函数返回之后,这个block失效了

     

    例子

    • void exampleC_addBlockToArray(NSMutableArray *array) {
    •   [array addObject:^{
    •     printf("C ");
    •   }];
    • }
    •  
    • void exampleC() {
    •   NSMutableArray *array = [NSMutableArray array];
    •   exampleC_addBlockToArray(array);
    •   void (^block)() = [array objectAtIndex:0];
    •   block();
    • }

    首先看这里的addObject这个block没有访问任何的外部变量,所以这是一个GlobalBlock,不管在ARC还是非ARC下,都是正确的。

     

    >>  为什么在使用property属性修饰block的时候,需要用到copy操作?

    在非ARC下,需要将block从栈中copy到堆中,避免被自动释放。对block 进行retain操作是无效的

    在ARC下,block会自动copy到堆中。

     

    >> Block循环引用问题(一定要是双方的)

    使用block的时候,经常会由于循环引用的问题导致内存无法释放,(对象拥有block,block又用到对象)

    比如

    self.myBlock = ^{ [self xxxxx];};

    这里myBlock是self的属性,而在myBlock里面又使用到了self;self在释放的时候必定要先释放myBlock,但是myBlock需要先释放里面的self,这样就导致死循环了。

     

    要打破这个格局,可以使用如下

    在ARC下:

    __weak typeof(self) weakSelf = self;

    self.myBlock = ^{ [weakSelf xxxxx];};

     

    如果在block里面会多次用到weakSelf 那应该使用如下的strongSelf

    __weak typeof(self) weakSelf = self;

    self.myBlock = ^{ 

    __strong typeof(self)strongSelf = weakSelf;

    [strongSelf xxxxx];

    [strongSelf bbbbb];

    };

     

    在非ARC下,直接将__weak改为__block就可以(__block typeof(self)weakSelf=self;)。

    所以__block的意思在ARC下只表示可修改;在非ARC下,表示可修改、不要retain这个变量.

     

    >> 在一个类中,并不是直接使用了self才会导致强引用self的。比如类中有一个实例变量 int value;

    那么在  dispatch_async(queue,^{    doSomthingWith(value); } );   这个时候用到了类的实例变量value,实际上也是强应用了 self。如果queue是类的成员变量,那就会出现死循环的问题。如果是这样  dispatch_async(dispatch_get_global_queue(0,0),^{    doSomthingWith(value); } ); 这个就是单向引用,不会造成死循环。

     

    >>  block与函数的区别

    block是对象,它封装了一段代码,这段代码可以在任何时候执行。block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或者返回值。

    block跟传统的函数指针很类似,但是block是内联的(inline),并且它对局部变量只是只读的。

     

    block可以访问局部变量,但是不能修改

    在需要修改的局部变量前加入__block

     

    定义一个block看上去像定义一个函数差不多,void(^bbb)(void)=^(int a){…..};

    但是还是有很大的区别的,block的定义可以在一个函数的内部实现。

     

    >> __block 与 __weak的区别

    __block 在ARC以及MRC模式下都可以使用。

    __weak是ARC模式下使用的,代表的是弱引用,防止循环引用。

    __block在非ARC下表示可以修改、如果修饰的是对象,表示不要retain(防止循环引用)

    __block对象在block中可以被重新赋值,__weak不可以。

     

  • 相关阅读:
    C#
    C#
    css
    css
    css
    css
    css
    Css
    Javascript
    ASP.NET MVC
  • 原文地址:https://www.cnblogs.com/rollrock/p/5113837.html
Copyright © 2020-2023  润新知