zoukankan      html  css  js  c++  java
  • Block使用中的一些要注意的地方

    本文主要是阐述一下Block中如何的使用外部变量以及block本身的内存管理。

    先定义一个block变量,作为后续的例子中使用:

    typedef void(^BlockCC)(void);
    BlockCC _block;
    

    1、block中引用外部变量

    block中可以直接使用外部的变量,比如

    int number = 1;
    _block = ^(){
        NSLog(@"number %d", number);
    };
    

    那么实际上,在block生成的时候,是会把number当做是常量变量编码到block当中。可以看到,以下的代码,block中的number值是不会发生变化的:

    int number = 1;
    _block = ^(){
        NSLog(@"number %d", number);
    };
    number = 2;
    _block();
    

    则输出的值为 1,而不是2。原因就是如上所说。

    如果要在block中尝试改变外部变量的值,则会报错的。对于这个问题的解决办法是引入__block标识符。将需要在block内部修改的变量标识为__block scope。更改后的代码如下:

    __block int number = 1;
    _block = ^(){
        number++;
        NSLog(@"number %d", number);
    };
    

    而这个时候,其实block外部的number和block内部的number指向了同一个值,回到刚才的在外部改变block的例子,它的输出结果将是2,而不是1。有兴趣的可以自己写一个例子试试。

    2、block自身的内存管理

    block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。比如下面的例子。
    我在view did load中创建了一个block:

    - (void)viewDidLoad
    {
        [superviewDidLoad];
    
        int number = 1;
        _block = ^(){
    
        NSLog(@"number %d", number);
    };
    }
    

    并且在一个按钮的事件中调用了这个block:

    - (IBAction)testDidClick:(id)sender {
        _block();
    }
    

    此时我按了按钮之后就会导致程序崩溃,解决这个问题的方法就是在创建完block的时候需要调用copy的方法。copy会把block从栈上移动到堆上,那么就可以在其他地方使用这个block了~
    修改代码如下:

    _block = ^(){
        NSLog(@"number %d", number);
    };
    
    _block = [_blockcopy];
    

    同理,特别需要注意的地方就是在把block放到集合类当中去的时候,如果直接把生成的block放入到集合类中,是无法在其他地方使用block,必须要对block进行copy。不过代码看上去相对奇怪一些:

    [array addObject:[[^{
        NSLog(@"hello!");
    } copy] autorelease]];
    

    3、循环引用

    这一点其实是在第一点的一个小的衍生。当在block内部使用成员变量的时候,比如

    @interface ViewController : UIViewController
    {
        NSString *_string;
    }
    @end
    

    在block创建中:

    _block = ^(){
        NSLog(@"string %@", _string);
    };
    

    这里的_string相当于是self->_string;那么block是会对内部的对象进行一次retain。也就是说,self会被retain一次。当self释放的时候,需要block释放后才会对self进行释放,但是block的释放又需要等self的dealloc中才会释放。如此一来变形成了循环引用,导致内存泄露。
    修改方案是新建一个__block scope的局部变量,并把self赋值给它,而在block内部则使用这个局部变量来进行取值。因为__block标记的变量是不会被自动retain的。

    __block ViewController *controller = self;
    _block = ^(){
        NSLog(@"string %@", controller->_string);
    };
    

    先写到这里,基本是我在用block时候碰到的一些问题。需要更详细的解释,可以看看《Adanced Mac OS X Programming》这本书,推荐给大家

  • 相关阅读:
    几个新角色:数据科学家、数据分析师、数据(算法)工程师
    人类投资经理再也无法击败电脑的时代终将到来了...
    Action Results in Web API 2
    Multiple actions were found that match the request in Web Api
    Routing in ASP.NET Web API
    how to create an asp.net web api project in visual studio 2017
    网站漏洞扫描工具
    How does asp.net web api work?
    asp.net web api history and how does it work?
    What is the difference between a web API and a web service?
  • 原文地址:https://www.cnblogs.com/akiha/p/5725377.html
Copyright © 2011-2022 走看看