zoukankan      html  css  js  c++  java
  • block 2 兼答疑

    之前简单的纪录过关于block的一些知识点,最近有人在回帖问了个问题。顺便温习了下,感觉内容放在现在有点单薄。

    于是结合提问,把相关的东西整理一下。

    问题简单的说:block内局部变量无法修改,但为什么可以添加数组?比如:

    NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"abc",nil];
    NSMutableArray *mArrayCount = [NSMutableArray arrayWithCapacity:1];
    [mArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock: ^(id obj,NSUInteger idx, BOOL *stop){
            [mArrayCount addObject:[NSNumber numberWithInt:[obj length]]];
        }];

    我觉得这个问题和block关系不大,根本是概念没有理清:

    1. OC中数组等对象,是一个指针
    2. 数组添加/删除对象,指针本身并没有变化

    因此,除非在block里对数组进行赋值,否则任何操作都是可行的。

    下面总结下,block下变量的访问权限:

    1. 相同作用域下,局部变量在block内是只读的
    2. 相同作用域下,带__block修饰的变量,在block内是可读写的
    3. 静态变量和全局变量在block内是可读写的。

    当block内使用了局部变量时,block会在栈上保存一份局部变量(block都是存储在栈上的),保存的变量在block里是一个常量,所以不能修改。

    若是OC中的对象,blcok会retain,等执行完毕后再release。

    如果有带__block的变量,那么block就可以对此变量进行修改。由此可见,带__block的变量不是线程安全的。iOS中,我们经常通过设置request的completionBlock来简化代码时,就需要注意到这一点。

    block保存相同作用域下局部变量的能力和JS中匿名函数的闭包特性有点类似,看一个例子:

    typedef void (^TestBlock) (void);
        int val = 20;
        TestBlock block1 = ^{ NSLog (@"%d", val); };
        val = 50;
        TestBlock block2 = ^{ NSLog (@"%d", val); };
        val = 5;
        TestBlock block3 = ^{ NSLog (@"%d", val); };
        block1();
        block2();
        block3();
        //output: 20 50 5

    仿照大多数js书上会举的例子,我们还有:

    TestBlock block[10];
        for (int i = 0; i < 10; i ++)
        {
            block[i] = ^{NSLog(@"the %d",i);};
            block[i]();
        }
        NSLog(@"After:\n");
        for (int i = 0; i < 10; i++)
        {
            block[i]();
        }

    所以要注意block的作用域。

    block本质上是对象,所以在OC中不得不提到内存管理。

    int localInt = 100;
        __block int blockInt = 0;
        TestBlock blockPtr = ^{
            blockInt += localInt;
    
        };

    如上的代码,所有的变量都存储在栈上。假如我们复制block:

    TestBlock blockCopy = block_copy(blockPtr);

    对于blockCopy,它也保存了局部变量localInt,但是localInt被“复制”后存储在堆里。同样的,blockInt也被“复制”存储在堆里。

    但是在栈上的blockInt会生成一个指针,指向新复制到堆上的blockInt。换言之,blockInt此时是一个“共享”变量。虽然使用copy的场景并不多见,但也是需要注意的地方。

    另外,Apple的文档里还提到:

    如果block访问到了类的实例变量,那么block会retain self本身。

    因为:

    var : self->var

    所以self会被retain,这种情况下有可能发生循环引用而使得内存不能释放,需要小心。

    有不对的地方,欢迎指正。

  • 相关阅读:
    16-爬虫之scrapy框架手动请求发送实现全站数据爬取03
    15-爬虫之scrapy框架基于管道实现数据库备份02
    14-爬虫之scrapy框架的基本使用01
    13-爬虫之js加密,解密,混淆,逆向破解思路
    12-基于selenium实现12306模拟登录,及京东登录滑动缺口验证模拟登录
    11-selenium浏览器自动化
    10-异步爬虫(线程池/asyncio协程)实战案例
    09-百度ai图片识别
    08-百度ai语音合成
    RNN
  • 原文地址:https://www.cnblogs.com/scorpiozj/p/3007310.html
Copyright © 2011-2022 走看看