Block Storage Domain Analysis

Then "Block intercepted automatic variables to achieve the realization of the internal __block modifier" We continue to explore Block

Leaving questions

  • 1 __Block_byref_i_0 *__forwarding; this pointer is pointing to itself what the hell, what role, when to use?
  • 2, Desc_0 structure in the extra void (*copy) void (*dispose)two methods What is the role, when to use?

Block essence of variables and __block

name substance
Block The stack structure example of Block
__block variable Examples of body structures on the stack variables __block

Block type

struct __ViewController__viewDidLoad_block_impl_0 {
  struct __block_impl impl;
  struct __ViewController__viewDidLoad_block_desc_0* Desc;
  __Block_byref_i_0 *i; // by ref
  __ViewController__viewDidLoad_block_impl_0(void *fp, struct __ViewController__viewDidLoad_block_desc_0 *desc, __Block_byref_i_0 *_i, int flags=0) : i(_i->__forwarding) {
    impl.isa = &_NSConcreteStackBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

We all know isa pointer is a pointer to its class, so impl.isa = &_NSConcreteStackBlock;it indicates that the Block is _NSConcreteStackBlocktype. Namely Block on the stack.

Of course

class Storage domain object Set
_NSConcreteStackBlock Stack
_NSConcreteGlobalBlock Data area of ​​the program (.data region)
_NSConcreteMallocBlock stack

Under what circumstances is _NSConcreteGlobalBlock type of Block

By name, global (global) we create a global Block, look at his results compiled


#import "ViewController.h"
//全局的Block
void (^blk)(void) = ^{NSLog(@"123");};

typedef void(^WxsBlock) ();

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    blk();
}

@end

Compiled


struct __blk_block_impl_0 {
  struct __block_impl impl;
  struct __blk_block_desc_0* Desc;
  __blk_block_impl_0(void *fp, struct __blk_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteGlobalBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};

static void __blk_block_func_0(struct __blk_block_impl_0 *__cself) {
    NSLog((NSString *)&__NSConstantStringImpl__var_folders_t9_g3xrsv653kz2gr7tmgwfbfvh0000gn_T_ViewController_fbc035_mi_0);}

static struct __blk_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __blk_block_desc_0_DATA = { 0, sizeof(struct __blk_block_impl_0)};

static __blk_block_impl_0 __global_blk_block_impl_0((void *)__blk_block_func_0, &__blk_block_desc_0_DATA);

void (*blk)(void) = ((void (*)())&__global_blk_block_impl_0)

we discoverimpl.isa = &_NSConcreteGlobalBlock;

We again from block as normal local variables, function return value, when the type of function parameters see it

Automatic variable taken


@property(nonatomic, assign) blk_t blockAssgin;
@property(nonatomic, strong) blk_t blockStrong;
@property(nonatomic, copy) blk_t blockCopy;


blk_t getBlk_t(int i) {
    blk_t block4 = ^(int count){return count*i;};
    NSLog(@"作为函数返回值,有自动变量截取---%@",block4);
     return block4;
}


{
    //作为普通变量, 有自动变量截取
    blk_t block1 = ^(int count) {
        return count * value;
    };
    NSLog(@"作为普通变量, 有自动变量截取---%@",block1);


    //作为assign类型成员变量 ,有自动变量截取
    self.blockAssgin = ^(int count) {
        return count * value;
    };
    NSLog(@"作为assign类型成员变量 ,有自动变量截取---%@",self.blockAssgin);

    //作为strong类型成员变量 ,有自动变量截取
    self.blockStrong = ^(int count) {
        return count * value;
    };
    NSLog(@"作为strong类型成员变量 ,有自动变量截取---%@",self.blockStrong);


    //作为copy类型成员变量 , 有自动变量截取
    self.blockCopy = ^(int count) {
        return count * value;
    };
    NSLog(@"作为copy类型成员变量 , 有自动变量截取---%@",self.blockCopy);

    //作为函数返回值,有自动变量截取
    getBlk_t(value);

    //作为函数参数,有自动变量截取
    [self actionBlock:^int(int i) {
        return i*value;
    }];
}

- (void)actionBlock:(blk_t)block {
    //作为函数参数,无自动变量截取
    NSLog(@"作为函数参数,有自动变量截取---%@",block);
    block(1);
}

NSLog 日志:

Block[47786:5956467] 作为普通变量,有自动变量截取---<__NSMallocBlock__: 0x60000024c9c0>
Block[47786:5956467] 作为assign类型成员变量,有自动变量截取---<__NSStackBlock__: 0x7fff5fbc39e0>
Block[47786:5956467] 作为strong类型成员变量,有自动变量截取---<__NSMallocBlock__: 0x608000056110>
Block[47786:5956467] 作为copy类型成员变量,有自动变量截取---<__NSMallocBlock__: 0x608000056620>
Block[47786:5956467] 作为函数返回值,有自动变量截取---<__NSMallocBlock__: 0x6080000565c0>
Block[47786:5956467] 作为函数参数,有自动变量截取---<__NSStackBlock__: 0x7fff5fbc3968>

However, the results compiled by the clang out, they all are all equally impl.isa = &_NSConcreteStackBlock;shocked not a surprise? Meaning no accident?

No automatic variable taken

{
    //作为返回值,无自动变量截取
    blk_t blockt = getBlk_t();
    NSLog(@"作为返回值,无自动变量截取blockt---%@",blockt);

    //作为普通变量,无自动变量截取,此处尝试了@property(strong,assgin,copy)这三种情况,是相同的结果
    self.blocktest = ^(int count){return count;};
    NSLog(@"作为普通变量,无自动变量截取----%@",self.blocktest);

    //作为函数参数,无自动变量截取
    [self actionBlock:^int(int i) {
        NSLog(@"%d",i);
        return i;
    }];
}

- (void)actionBlock:(blk_t)block {
    //作为函数参数,无自动变量截取
    NSLog(@"作为函数参数,无自动变量截取---%@",block);
    block(1);
}

打印结果
Block[47535:5919554] 作为返回值,无自动变量截取blockt---<__NSGlobalBlock__: 0x1039fd0f0>
Block[47535:5919554] 作为普通变量,无自动变量截取----<__NSGlobalBlock__: 0x1039fd150>
Block[47535:5919554] 作为函数参数,无自动变量截取---<__NSGlobalBlock__: 0x1039fd190>


全部是GlobalBlock

However, the results compiled by the clang out, they all are all equally impl.isa = &_NSConcreteStackBlock;shocked not a surprise? Meaning no accident?

By compiling clang only see in ARC Block type the static case (static code statement), I feel only as a reference, there is still running.

So we can print the results of the NSLog briefly summarize:

Block type Whether the automatic variable interception Usage
_NSConcreteGlobalBlock Have As a global variable declaration and initialization
no All cases
NSStackBlock Have assgin member variable of type
As a function parameter
no no
_NSConcreteMallocBlock Have As an ordinary local variables
As a member variable of type copy
As a member variable of the type of strong
As a function return value
no no

Why _NSConcreteGlobalBlock type Block to be set in the data area?

Because in place using global variables will not be automatically intercepted variables. Because it is a beginning it has been defined. There is no "variable", so its execution is fixed at any time and run-time environment does not depend on the operation of this type is only one global can not only save space and good management. So on the global static data area of ​​the region better and better.

By contrast clang compiled and summarized the NSLog

By clang compiled results, except when the global variable declaration and creation of the block is compiled into _NSConcreteGlobalBlockother times are all _NSConcreteMallocBlocktypes, we can see that the initial state of Block's only two, so Block Malloc state is from Stack state change the past, and the author of this conjecture also coincides watching "Objective-C high-level programming" time.

So we're going to explore how it is got from the stack to the heap.

The "Objective-C level programming" Description:
It is obtained by objc_retainBlock()a method to get the Block stack from the stack,
seen by the runtime / objc-arr.mm objc4 runtime:
objc_retainBlock()=_Block_copy

When a Block is why as a function of the return value is got heap, it was done?

blk_t func(int rate) {

    /*
        通过Block语法生成Block,配置在栈上的结构体实例,
        tmp被赋值
    */
    blk_t tmp = &__func_block_impl_0(...);

   /*
    通过_Block_copy将其复制到堆上
    复制后将堆上的地址作为指针复制给变量tmp
   */
    tmp = _Block_copy(tmp);

   /*
    将堆上的Block作为Objective—C对象
    注册到autoreleasepool中,返回该对象
   */
    return objc_autoreleaseReturnValue(tmp);
}

Copied in the ARC Block operation is get their own compiler, but the compiler is not a panacea

When used as a return value, the compiler apparently can handle

But then as a function of time is not very good argument to make, and this time we need to manually copy Block, that by "as an argument, automatic variable intercept" Verify that the instance has been verified, it is the type of stack

Here is sure to be asked, why do we have to copy the heap? ? It is not on the stack?

Liang Zi: Security!
Copied onto the heap of __block Block variables and variables are not affected at the end of variable scope

When do you need to manually Copy

Heavy or method parameters passed to Block Function

However, if the appropriate copy of the passed parameters in a method or function, then it is not necessary to call this method before or function manually copied, such as what method:

When the method name and method 1, Cocoa frame has usingBlock like
2, GCD of API

Published 139 original articles · won praise 35 · views 410 000 +

Guess you like

Origin blog.csdn.net/wxs0124/article/details/70332601