We know that the application’s memory allocation has four extents:

  • Program area (.text area) – Holds the binary code of the function body.
  • Data area (.data area) – mainly includes the static global area (global variables and static variables are stored in the same area, initialized global variables and static variables in the same area, uninitialized global variables and uninitialized static variables in another area adjacent to the end of the system release.) And constant fields (where constant strings are placed. The program is released by the system after completion. , if you want to stand in the assembly of subdivision can also be divided into a lot of small areas.
  • Heap – Usually allocated to be released by the programmer. If not released by the programmer, it may be reclaimed by the operating system at the end of the program. Note that this is not the same thing as a heap in a data structure and is allocated in a similar way to a linked list. First in, first out (FIFO).
  • Stack – Automatically allocated by the compiler to hold function parameter values, local variable values, etc. It operates like a stack in a data structure. Last in first out (LIFO).

On which region is a block created as an OC object? Let’s explore that in this article.

Type of block object

A block is an NSBlock object, which is declared as follows:

@interface NSBlock : NSObject <NSCopying>

+ (id)alloc;
+ (id)allocWithZone:(struct _NSZone { }*)arg1;

- (id)copy;
- (id)copyWithZone:(struct _NSZone { }*)arg1;
- (void)invoke;
- (void)performAfterDelay:(double)arg1;

@end
Copy the code

NSBlock has three subclasses:

  • _NSConcreteGlobalBlock – Data section (.data section)
  • Heap _NSConcreteMallocBlock –
  • _NSConcreteStackBlock stack –

Let’s look at each of these blocks.


1.1 _NSConcreteGlobalBlock

_NSConcreteGlobalBlock, as the name implies, global block. When initializing a block, the resulting block is _NSConcreteGlobalBlock:

  • Initialize the Block in place of the life global variable;
  • Do not capture non-static local variables.

The code is as follows:

/** global variables */
int global_count = 10;
/** static global variable */
static int static_global_count = 10;

int main(int argc, const char * argv[]) {
    
    /** static local variable */
    static int static_count = 10;
    
    void (^block)(void) = ^ {
        global_count = 11;
        static_global_count = 11;
        static_count = 11;
    };
    
    block();
    return 0;
}

Copy the code

Concreteglobalblock = _NSConcreteGlobalBlock;


1.2 _NSConcreteStackBlock

_NSConcreteStackBlock is a stack block. In an ARC environment, any block that captures local variables, member variables, and is not strongly referenced is _NSConcreteStackBlock.

1.2.1 Capturing local variables

OC code is as follows:

int main(int argc, const char * argv[]) {

    /** Local variable */
    int count = 10;
    
    /** Executes or uses void (^__weak block)(void) to point to block */^ {NSLog(@"%d", count); } ();// Prints Block objects
    NSLog(Block object: %@The ^ {NSLog(@"%d", count);
    });

    return 0;
}
Copy the code

The console displays the following information:

Block object: <__NSStackBlock__: 0x7ffeefbff568>Copy the code

1.2.2 Capturing member variables

OC code is as follows:

@interface ViewController(a)

@property (nonatomic.assign) int count;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSLog(Block object: %@The ^ {NSLog(@"%d".self.count); }); ^ {NSLog(@"%d".self.count); } (); }@end
Copy the code

The console displays the following information:

Block object: <__NSStackBlock__: 0x7ffee554b838>Copy the code

In summary, the content of a block implementation depends on the state at execution time, is not strongly referenced, and is only scoped to the current function. The block is _NSConcreteStackBlock and is stored on the stack.


1.3 _NSConcreteMallocBlock

Nsconcretemallocblock is a heap block and is a wide area variable. Will be saved on the heap in the following cases:

  • As the return value of a function;
  • Cocoa framework method and method hit contains usingBlock etc. (to be verified);
  • Grand Central Dispatch API (to be confirmed);
  • Etc.

1.3.1 as the return value of the function

When a block is returned as a function, the ARC environment will automatically copy the block, expand the scope, OC code is as follows:

/** function creates */
typedef void (^block)(void);
block function(int num) {
    return^ {NSLog(@"%d", num);
    };
}

int main(int argc, const char * argv[]) {
    
    // The function returns the value assigned
    void(^ __weak block1)(void) = function(10);
    
    // Prints the block1 object
    NSLog(Block1 object: %@", block1);
    
    return 0;
}
Copy the code

The console prints the following result:

Block1 object: <__NSMallocBlock__: 0x103804d30>Copy the code

To sum up: since the block is used as a local variable in the function, if we do not copy it, the block will be destroyed when the function returns, so the system will automatically copy the block for us under ARC, but the MRC system will directly compile the error, so we need to manually copy the block.


There is no time to confirm that the system automatically copies the block as a parameter. I will fill in this part later. I’m sorry…

1.3.2 Copying effects of the three Blocks

Without further ado, go straight to the table:

Block of the class The configuration storage domain of the copy source Effect of assignment
_NSConcreteGlobalBlock Data area Do nothing
_NSConcreteStackBlock The stack Copy from stack to heap
_NSConcreteMallocBlock The heap Reference count increment

The reason _NSConcreteGlobalBlock in the data area does nothing is that it is not needed, because _NSConcreteGlobalBlock is destroyed after the process ends and is already a wide area variable.

1.4 summarize

There are several ways to determine what type of variable a block is:

  • 1: if no variables are captured or static/global variables are captured (variables are stored in the data area)_NSConcreteGlobalBlock
  • 2: if local variables are captured (stored on the stack or heap) and are not strongly referenced_NSConcreteStackBlock
  • 3: If yes_NSConcreteStackBlockAnd is strongly referenced_NSConcreteMallocBlock