zoukankan      html  css  js  c++  java
  • Block(二)内存管理与其他特性-b

    一、block放在哪里

    我们针对不同情况来讨论block的存放位置:

    1.栈和堆

    以下情况中的block位于堆中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    void foo()
    {
        __block int i = 1024;
        int j = 1;
        void (^blk)(void);
        void (^blkInHeap)(void);
        blk = ^{ printf("%d, %d ", i, j);};//blk在栈里
        blkInHeap = Block_copy(blk);//blkInHeap在堆里
    }
     
    - (void)fooBar
    {
        _oi = 1;
        OBJ1* oj = self;
        void (^oblk)(void) = ^{ printf("%d ", oj.oi);};
        void (^oblkInHeap)(void) = [oblk copy];//oblkInHeap在堆中
    }

    2.全局区

    以下情况中的block位于全局区: 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    static int(^maxIntBlock)(int, int) = ^(int a, int b){return a>b?a:b;};
    - (void)fooBar
    {
         int(^maxIntBlockCopied)(int, int) =[maxIntBlock copy];
    }
     
    void foo()
    {
         int(^maxIntBlockCopied)(int, int) = Block_copy(maxIntBlock);
    }

    需要注意的是,这里复制过后的block依旧位于全局区,实际上,复制操作是直接返回了原block对象。 

    二、block引用的变量在哪里

     1.全局区

    全局区的变量存储位置与block无关:

    1
    2
    3
    4
    5
    6
    7
    8
    static int gVar = 0;
    //__block static int gMVar = 1;
     
    void foo()
    {
        static int stackVar = 0;
    //    __block static int stackMVar = 0;
    }

    注意,static变量是不允许添加__block标记的

    2.堆栈 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    void foo()
    {
        __block int i = 1024;//此时i在栈上
        int j = 1;//此时j在栈上
        void (^blk)(void);
        blk = ^{printf("%d, %d ", i, j); };//此时,blk已经初始化,它会拷贝没有__block标记的常规变量自己所持有的一块内存区,这块内存区现在位于栈上,而对于具有__block标记的变量,其地址会被拷贝置前述的内存区中
        blk();//1024, 1
        void(^blkInHeap)(void) = Block_copy(blk);//复制block后,block所持有的内存区会被拷贝至堆上,此时,我们可以说,这个block现在位于堆上
        blkInHeap();//1024,1
        i++;
        j++;
        blk();//1025,1
        blkInHeap();//1025,1
    }

    让我们一步步剖析:

    首先,我们在栈上创建了变量ij,并赋予初始值,然后创建一个block变量名为blk,但未赋值。

    然后我们初始化这个blk,赋值为一个只有一句printf的block,值得注意的是,一个block一旦创建,其引用到的常规变量会进行如下操作:

    没有__block标记的变量,其值会被复制一份到block私有内存区

    有__block标记的变量,其地址会被记录在block私有内存区

    然后调用blk,打印1024, 1很好理解

    接下来复制blk到堆,名曰blkInHeap,调用之,打印1024, 1也很好理解

    接下来我们为ij增值,使其变为1025和2,此时再调用blk或者blkInHeap,会发现结果为1025, 1,这是因为变量j早已在创建原始的block时,被赋值进block的私有内存区,后续对i的操作并非操作的私有内存区的复制品,当调用blk或者blkInHeap时,其打印使用的是私有内存区的复制品,故而打印结果依旧为1;而变量j的修改会实时生效,因为block记录的是它的地址,通过地址来访问其值,使得外部对j的修改在block中得以生效。对于变量i来讲,可算是物是人非吧?

    因此,无论j++这一句放到blk()这句之前或者之后,只要它位于block初始化之后,这段代码执行的控制台打印结果都会是:1024, 1。而不是1024, 2(假设不调用i++)

  • 相关阅读:
    剑指Offer:面试题17——合并两个排序的链表
    剑指Offer:面试题16——反转链表(java实现)
    剑指Offer:面试题15——链表中倒数第k个结点(java实现)
    Timer和TimerTask 定时器和定时任务
    Spring-WebSocket 教程
    单点登录原理与简单实现
    Python机器学习:泰坦尼克号获救预测一
    转 smarty学习笔记电子版整理
    转 nodejs socket.io初探
    html5新增的属性和废除的属性
  • 原文地址:https://www.cnblogs.com/isItOk/p/8108263.html
Copyright © 2011-2022 走看看