Blocks Programming Topics

Block objects are C syntax and a runtime feature. They are similar to standard C functions, but in addition to executable code they may also contain variable bindings to automatic (stack) or managed (heap) memory. Therefore, a Block can maintain a set of state (data) that can be used to influence execution behavior when the Block is executed

Blocks can be used to form function expressions that can be passed to the API (blocks can be used as interface arguments) to store data. They can be used in multiple threads. Blocks are particularly useful as callbacks because they contain both the code to be executed on the callback and the data needed during execution

The OS X V10.6 Xcode Developer tools ship with blocks in GCC and Clang and can be used in OS X V10.6 and later as well as iOS 4.0 and later, Block runtime is open source and can be found in LLVM’s Compiler-RT subproject Repository. Blocks have also been submitted to the C Standards Working Group as N1370: Apple’s Extensions to C, and since both Objective-C and C++ are derived from C, blocks are designed to work with all three languages (as well as Objective-C++)

Getting Started with Blocks

Declaring and Using a Block

Use the ^ operator to declare a block variable and indicate the beginning of the block literal. The body of the block itself is contained in {}

int multiplier = 7;
int (^myBlock)(int) = ^ (int num) {
    return num * multiplier;
};
Copy the code

Notice that a block can use variables within its definition

If you declare a block as a variable, you can use it like a function

int multiplier = 7;
int (^myBlock)(int) = ^ (int num) {
    return num * multiplier;
};
 
printf("%d", myBlock(3));
// prints "21"
Copy the code

Using a Block Directly

In many cases, you do not need to declare a block variable. Instead, you simply write inline code blocks where you need them as arguments. The example uses the qsort_b function, which is similar to the standard qsort_r function but takes a block as one of its arguments

char *myCharacters[3] = { "TomJohn"."George"."Charles Condomine" };
 
qsort_b(myCharacters, 3.sizeof(char*), ^ (const void *l, const void *r) {
    char *left = *(char **)l;
    char *right = *(char **)r;
    return strncmp(left, right, 1);
});
 
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
Copy the code

Blocks with Cocoa

Several methods is to a block of the Cocoa framework as a parameter, usually do perform operations to the object collection, and used as a callback after operation is completed, the following example shows how to block and sortedArrayUsingComparator NSArray method: used together

NSArray *stringsArray = @[ @"string 1".@"String 21".@"string 12".@"String 11".@"String 02" ];
 
static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch |
        NSWidthInsensitiveSearch | NSForcedOrderingSearch;
NSLocale *currentLocale = [NSLocale currentLocale];
 
NSComparator finderSortBlock = ^(id string1, id string2) {
 
    NSRange string1Range = NSMakeRange(0, [string1 length]);
    return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];
};
 
NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock];
NSLog(@"finderSortArray: %@", finderSortArray);
 
/* Output: finderSortArray: ( "string 1", "String 02", "String 11", "string 12", "String 21" ) */
Copy the code

__block Variables

The power of a block is that it can modify variables within the same lexical scope. Using the __block store type modifier to indicate that a block can modify variables. Following the previous example, a block variable can be used to calculate a relatively equal number of strings, in which case the block will be used directly. And use currentLocale as a read-only variable within that block

NSArray *stringsArray = @[ @"string 1".@"String 21".// <-
                          @"string 12".@"String 11".@ "String 21".// <-
                          @ "String 21".// <-
                          @"String 02" ];
 
NSLocale *currentLocale = [NSLocale currentLocale];
__block NSUInteger orderedSameCount = 0;
 
NSArray *diacriticInsensitiveSortArray = [stringsArray sortedArrayUsingComparator:^(id string1, id string2) {
 
    NSRange string1Range = NSMakeRange(0, [string1 length]);
    NSComparisonResult comparisonResult = [string1 compare:string2 options:NSDiacriticInsensitiveSearch range:string1Range locale:currentLocale];
 
    if (comparisonResult == NSOrderedSame) {
        orderedSameCount++;
    }
    return comparisonResult;
}];
 
NSLog(@"diacriticInsensitiveSortArray: %@", diacriticInsensitiveSortArray);
NSLog(@"orderedSameCount: %d", orderedSameCount);
 
/* Output: diacriticInsensitiveSortArray: ( "String 02", "string 1", "String 11", "string 12", "String 21", "Str\U00eeng 21", "Stri\U00f1g 21" ) orderedSameCount: 2 */
Copy the code

Conceptual Overview

Block objects provide a way to create temporary function bodies that are created in C as well as expressions in C-based languages such as Objective-C and C ++. In other languages and environments, block objects are sometimes called “closures”.

Block Functionality

A block is a collection of anonymous inline code

  • Has a typed parameter list like a function
  • Has an inferred or declared return type
  • From the vocabulary that defines it (lexical scope)
  • The lexical range can be selectively modified (lexical scopeThe state of)
  • Modified variables can be shared with other blocks defined in the same vocabulary
  • The state defined in the lexical scope (stack space) can continue to be shared and modified after the lexical scope (stack space) is destroyed

A block can be copied, but it can also be passed to another thread to delay execution (or to the run loop in its own thread), and the compiler and runtime can ensure the lifetime of all variables referenced by the block, Although blocks can be used in pure C and C++, blocks are always Objective-C objects

Usage

Blocks typically stand for small, independent pieces of code. They are therefore particularly useful for encapsulating units of work that can be executed simultaneously, items in collections, and callbacks after other operations have been completed

Blocks can be used as an alternative to traditional callback schemes for two important reasons

  • They allow code to be written at the point of invocation that is later executed in the context of the method implementation, so blocks are usually common arguments to methods in the framework
  • They allow access to local variables

Declaring and Creating Blocks

Declaring a Block Reference

Block variables hold references to block objects. They are declared using a syntax similar to that used to declare function Pointers, except that ^ is used instead of *. Block types can interoperate fully with the rest of the C-type system

void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int.char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10]) (int);
Copy the code

Block also supports variable arguments (…) , blocks without arguments must specify void in the argument list

Blocks are designed to be fully type-safe by providing the compiler with a set of metadata that validates their use, including the parameters passed to the block and the assignment of return values. A block reference can be cast to a pointer of any type and vice versa

However, you cannot dereference a block through the pointer reference operator *, because the size of the block cannot be calculated at compile time

You can create types for blocks so that they can be used in multiple places

typedef float (^MyBlockType)(float.float);
 
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;
Copy the code

Creating a Block

You can use the ^ operator to indicate the beginning of a literal block expression, which can be followed by a list of arguments contained in (). The body of the block is contained in {}

The sample

float (^oneFrom)(float);
 
oneFrom = ^(float aFloat) {
    float result = aFloat - 1.0;
    return result;
};
Copy the code

If the return value of a block expression is not explicitly declared, it can be inferred automatically from the contents of the block. If both the return type and argument list are inferred to be void, the void argument list can also be omitted. If multiple return statements exist, they must match exactly (cast if necessary).

Global Blocks

Blocks can be used as global variables at the file level

#import <stdio.h>
 
int GlobalInt = 0;
int (^getGlobalInt)(void) = ^ {return GlobalInt; };
Copy the code

Blocks and Variables

Types of Variable

Inside the code of a block object, variables can be handled in five different ways

There are three standard types of variables that can be referenced, just as in functions

  • Global variables, including static local variables
  • Global functions (not technically mutable)
  • Local variables and parameters from a closed scope

Blocks also support two other types of variables

  • At the function level, theta__blockVariables, which are mutable within blocks (and enclosed ranges), are retained if any reference blocks are copied to the heap
  • constconstant

Finally, in method implementation, blocks can reference Objective-C instance variables

Rules for variables used in blocks

  • Global variables are accessible, including static variables that are contained within the vocabulary

  • The arguments passed to a block are accessible (just like the arguments to a function)

  • A non-static local variable in a closed range is captured by the block asconstImmutable constant, immutable

    • The position of block expressions in the program gets their values
    • Captures a value from the nearest enclosing range in a nested block
  • Local variables enclosing lexical scope, declared with the __block store modifier, are mutable and can be modified

    • Any changes affect the contents of the lexical association, including any other blocks defined within the same closed lexical scope
  • A local variable declared within the lexical scope of a block behaves like a local variable in a function

Use local non-static variables

int x = 123;
 
void (^printXAndY)(int) = ^ (int y) {
 
    printf("%d %d\n", x, y);
};
 
printXAndY(456); // prints: 123 456
Copy the code

Attempting to assign a new value to x within a block results in an error

int x = 123;
 
void (^printXAndY)(int) = ^ (int y) {
 
    x = x + y; // error
    printf("%d %d\n", x, y);
};
Copy the code

The __block Storage Type

By applying the __block store type modifier, you can specify that imported variables are mutable (readable and writable). __block is similar to register, auto, and static for local variables, but is mutually exclusive with them

__block variables are stored in a store shared between the lexical scope of the variable and all blocks and copies of blocks declared or created within the lexical scope of the variable, so that any copy of a block declared inside the stack survives at the end of the stack (e.g., By queuing up somewhere for later execution), the storage will avoid stack destruction (Thus, the storage will survive the destruction of the stack frame if any copies of the blocks declared within the frame survive beyond the end of the frame (for example, by being enqueued somewhere for later execution). Multiple blocks within a given lexical range can use shared variables simultaneously

As an optimal item, blocks are generally used on the stack. If a block is copied using Block_copy (or a copy message is sent in Objective-C), the copied content is on the heap, so the address of the __block-modified variable can change over time

The __block variable also has two limitations

  • They cannot be variable-length arrays
  • Cannot be a structure containing a C99 variable length array

__blockThe sample

__block int x = 123; // x lives in block storage
 
void (^printXAndY)(int) = ^ (int y) {
 
    x = x + y;
    printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 579 456
// x is now 579
Copy the code

The following example shows blocks with multiple types of variables

extern NSInteger CounterGlobal;
static NSInteger CounterStatic;
 
{
    NSInteger localCounter = 42;
    __block char localCharacter;
 
    void (^aBlock)(void) = ^ (void) {
        ++CounterGlobal;
        ++CounterStatic;
        CounterGlobal = localCounter; // localCounter fixed at block creation
        localCharacter = 'a'; // sets localCharacter in enclosing scope
    };
 
    ++localCounter; // unseen by the block
    localCharacter = 'b';
 
    aBlock(); // execute the block
    // localCharacter now 'a'
}
Copy the code

Object and Block Variables

Blocks as variables provide support for Objective-C and C++ objects, as well as other blocks

Objective-C Objects

When a block is copied, it creates a strong reference to the object variable used within the block, if the block is used within the implementation method

  • If an instance variable is accessed by reference, theselfStrong reference
  • ** If an instance variable is accessed by value, it is strongly referenced

The following example illustrates two different situations

dispatch_async(queue, ^{
    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});
 
 
id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /* localVariable is used by value, a strong reference is made to localVariable (and not to self). */
    doSomethingWithObject(localVariable);
});
Copy the code

C++ Objects

It is usually possible to use C++ objects within a block. In member functions, references to member variables and functions are made by implicitly importing the this pointer, so they look mutable. There are two caveats if you copy blocks

  • If I have one__blockClasses that store types to handle stack-based C++ objects, usually copy constructors will be used
  • If you use any other C++ stack-based object in a block, it must have oneconstCopy the constructor, and then use it to copy the C++ object

Blocks

When a block is copied, any references to other blocks in that block are copied if necessary. If a block variable is copied and the block references other blocks, the referenced block is copied as well

Using Blocks

Invoking a Block

A block can be used as a function if it is declared as a variable, as shown in the example

int (^oneFrom)(int) = ^ (int anInt) {
    return anInt - 1;
};
 
printf("1 from 10 is %d", oneFrom(10));
// Prints "1 from 10 is 9"
 
float (^distanceTraveled)(float.float.float) = ^ (float startingSpeed, float acceleration, float time) {
 
    float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
    return distance;
};
 
float howFar = distanceTraveled(0.0.9.8.1.0);
/ / howFar = 4.9
Copy the code

A block is usually passed as an argument to a function or method, in which case an inline block is usually created

Using a Block as a Function Argument

In many cases, you do not need to declare a block variable. Instead, you simply write inline code blocks where you need them as arguments. The example uses the qsort_b function, which is similar to the standard qsort_r function but takes a block as one of its arguments

char *myCharacters[3] = { "TomJohn"."George"."Charles Condomine" };
 
qsort_b(myCharacters, 3.sizeof(char*), ^ (const void *l, const void *r) {
    char *left = *(char **)l;
    char *right = *(char **)r;
    return strncmp(left, right, 1);
});
 
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
Copy the code

The following is an example of a block used by the dispatch_apply function

void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

#include <dispatch/dispatch.h>
size_t count = 10;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 
dispatch_apply(count, queue, ^(size_t i) {
    printf("%u\n", i);
});
Copy the code

Using a Block as a Method Argument

Cocoa provides a number of methods that use blocks, which can be passed as a method argument just like any other argument

NSArray *array = @[@"A".@"B".@"C".@"A".@"B".@"Z".@"G".@"are".@"Q"];
NSSet *filterSet = [NSSet setWithObjects: @"A".@"Z".@"Q".nil];
 
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);
 
test = ^(id obj, NSUInteger idx, BOOL *stop) {
 
    if (idx < 5) {
        if ([filterSet containsObject: obj]) {
            return YES; }}return NO;
};
 
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];
 
NSLog(@"indexes: %@", indexes);
 
/*
Output:
indexes: <NSIndexSet: 0x10236f0>[number of indexes: 2 (in 2 ranges), indexes: (0 3)]
*/

/ / = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

__block BOOL found = NO;
NSSet *aSet = [NSSet setWithObjects: @"Alpha".@"Beta".@"Gamma".@"X".nil];
NSString *string = @"gamma";
 
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
    if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
        *stop = YES;
        found = YES; }}];// At this point, found == YES
Copy the code

Copying Blocks

There is usually no need to copy (or keep) a block, only if you want the block to be used after the block’s scoped destruction has been declared, and the copied block is produced on the heap

Blocks can be copied and released using C functions

Block_copy();
Block_release();
Copy the code

To avoid memory leaks, Block_copy() and Block_release() must always be balanced

Patterns to Avoid

A block literal (that is, ^{ … }) is the address of a stack-local data structure that represents the block. The scope of the stack-local data structure is therefore the enclosing compound statement, so you should avoid the patterns shown in the following examples:

Block text (that is ^ {… }) is the address of the stack local data structure representing the block, so the scope of the stack local data structure is a closed compound declaration, so the pattern shown in the following example should be avoided.

void dontDoThis(a) {
    void (^blockArray[3]) (void);  // an array of 3 block references
 
    for (int i = 0; i < 3; ++i) {
        blockArray[i] = ^{ printf("hello, %d\n", i); };
        // WRONG: The block literal scope is the "for" loop.}}void dontDoThisEither(a) {
    void (^block)(void);
 
    int i = random():
    if (i > 1000) {
        block = ^{ printf("got i at: %d\n", i); };
        // WRONG: The block literal scope is the "then" clause.
    }
    // ...
}
Copy the code

Debugging

Breakpoints can be set and step, and invoke-block can be used to invoke a block from a GDB session

$ invoke-block myBlock 10 20
Copy the code

A C string must be referenced if it is to be passed

$ invoke-block doSomethingWithString "\"this string\""
Copy the code

Effictive Objective-C 2.0 introduction to blocks

Each Objective C object occupies a certain amount of memory, depending on the number of instance variables and the associated data that the object contains. Block itself is also an object, and the first variable in the memory region that holds fast objects is a pointer to the Class object. This pointer is called ISA, and the rest of the memory contains all the information that the block object needs to function properly. The memory layout of the block object is depicted in the figure above

  • invokeVariable, which is a function pointer to the block’s implementation code, and the function prototype needs to receive at least onevoid *Type, which represents the block itself
  • descriptorA variable is a pointer to a structure that is contained in each block, declares the overall size of the block object, and declarescopyanddisposeFunction Pointers to these two helper functions. The helper functions run when a block object is copied and discarded, and perform operations such as:copyTo preserve the captured object, anddisposeRelease it

The block also makes a copy of all the variables that it captures, and it puts them after the descriptor variables, and it takes up as much memory as it captures, and notice that it’s not copying the object itself, it’s copying the pointer variables that point to those objects, and when you execute the block object, All of these captured variables are read out of memory

Stack block

  • When a block is defined, the area of memory it occupies is allocated on the stack, and a block is only valid for as long as it is defined
  • The compiler assigns stack memory to each block, and when it leaves the corresponding range, the compiler may overwrite the memory allocated to the block

Heap block

  • Give stack block executioncopyAction, you can copy blocks from the stack to the heap, and the copied block can be used outside the scope in which it was defined
  • Once the block is copied to the heap,Blocks become reference-counted objectsAnd the subsequentcopyNone of the operations actually perform copying, just incrementing the reference count of the block object
  • If heap blocks are no longer in use, they should be released, and manual management of reference counting needs to be invokedreleaseMethod, the reference count is0, the memory space is reclaimed by the system

Global block

  • No state is captured (external variables are captured), and the runtime does not require a stateful block to participate in
  • The entire memory area used by a block is fully determined by the compiler, so global blocks can be declared in global memory and do not need to be created on the stack each time they are used
  • Global blockcopyThe operation is an empty operation because the global block is not reclaimed by the system and is equivalent to a singleton

Global Block Example

void (^GlobalBlock)(void) {
    NSLog(@"This is a global block");
}
Copy the code

Objective-c advanced programming iOS and OS X multithreading and memory management Block introduction

The name of a Block in another programming language

Programming language The name of the Block
C + Blocks Block
Smalltalk Block
Ruby Block
LISP Lambda
Python Lambda
C++11 Lambda
Javascript Anonymous function

Intercept automatic variables (automatic variables — local variables in the book)

An example of an intercepted automatic variable value is as follows

int main(a) {
    int dmy = 256;
    int val = 10;
    const char *fmt = "val = %d\n";
    void (^blk)(void) = ^ {printf(fmt, val); }; val =2;
    fmt = "These values were changed. val = %d\n";

    blk();
    // Prints val = 10

    return 0;
}
Copy the code

In the source code above, Block syntax expressions use its previously declared automatic variables FMT and val

  • Block expressions capture the value of the used automatic variable and store the transient value of the automatic variable
  • Overwriting the values of automatic variables used in a Block after the execution of a Block syntax expression (after the Block definition) does not affect the values of automatic variables when the Block is executed. The result is that the execution of the Block syntax is the instantaneous value of automatic variables

__block qualifier

In fact, the value captured by an automatic variable can only be saved as soon as the Block syntax is executed, and cannot be overwritten. To change the value of a captured variable within a Block, you need to add a __block modifier

The realization of the Block

To view the C++ source implementation of block, you can use clang compiler instructions

Clang-rewrite-objc source code fileCopy the code
int global_val = 1;
static int static_global_val = 2;

int main() {
   int val = 10;
   static int static_val = 3;
   __block int block_val = 4;
   __block NSObject *instance_val = [[NSObject alloc] init];
   void (^blk)(void) = ^{
       global_val *= 1; // Global variables
       static_global_val *= 2; // Global static variables
       static_val *= 3; // Local static variables
       block_val = 1; // __block decorates a variable
       instance_val = [[NSObject alloc] init]; / / object
       printf("val: %d, block_val: %d\n", val, block_val);
   };

   val = 2;
   block_val = 3;

   blk();
   return 0;
}
Copy the code

C + + source code

int main(a) {
   int val = 10;
   static int static_val = 3;
   __attribute__((__blocks__(byref))) __Block_byref_block_val_0 
   block_val = {(void*)0,
                (__Block_byref_block_val_0 *)&block_val, 
                0.sizeof(__Block_byref_block_val_0), 
                4};
                
   __attribute__((__blocks__(byref))) __Block_byref_instance_val_1 
   instance_val = {(void*)0,
                    (__Block_byref_instance_val_1 *)&instance_val, 
                    33554432.sizeof(__Block_byref_instance_val_1),
                    __Block_byref_id_object_copy_131,
                    __Block_byref_id_object_dispose_131, 
                    ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"))};
                    
                    
   void (*blk)(void) = ((void (*)())&__main_block_impl_0((void*)__main_block_func_0, 
                                                          &__main_block_desc_0_DATA, 
                                                          &static_val, 
                                                          val, 
                                                          (__Block_byref_block_val_0*)&block_val, 
                                                          (__Block_byref_instance_val_1 *)&instance_val, 
                                                          570425344));

   val = 2;
   (block_val.__forwarding->block_val) = 3;

   ((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);

    return 0;
}
Copy the code

__main_block_impl_0structure

struct __main_block_impl_0 {
  struct __block_impl impl;
  struct __main_block_desc_0* Desc;

  // local static variable pointer type reference
  int *static_val;

  // General local variables
  int val;

  // The __block variable
  __Block_byref_block_val_0 *block_val; // by ref
  // The __block object
  __Block_byref_instance_val_1 *instance_val; // by ref

  // Initialize the constructor
  __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_static_val, int _val, __Block_byref_block_val_0 *_block_val, __Block_byref_instance_val_1 *_instance_val, int flags=0) : static_val(_static_val), val(_val), block_val(_block_val->__forwarding), instance_val(_instance_val->__forwarding) {
    impl.isa = &_NSConcreteStackBlock; // isa points to the type to which it belongs, where block is an objectimpl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }};Copy the code

__main_block_func_0 function

// The function called when the block executes
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
  __Block_byref_block_val_0 *block_val = __cself->block_val; // bound by ref
  __Block_byref_instance_val_1 *instance_val = __cself->instance_val; // bound by ref
  int *static_val = __cself->static_val; // bound by copy
  int val = __cself->val; // bound by copy
       
       // Global variables
       global_val *= 1;

       // Global static variables
       static_global_val *= 2;

       // Local static variables
       (*static_val) *= 3;

       / / __block variables
       (block_val->__forwarding->block_val) = 1;

       / / __block object
       (instance_val->__forwarding->instance_val) = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("alloc")), sel_registerName("init"));
       printf("val: %d, block_val: %d\n", val, (block_val->__forwarding->block_val));
   }
Copy the code

__main_block_desc_0_DATAThe structure of the body

static struct __main_block_desc_0 {
  size_t reserved;
  size_t Block_size;
  void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
  void (*dispose)(struct __main_block_impl_0*);
} __main_block_desc_0_DATA = { 0.sizeof(struct __main_block_impl_0), 
                               __main_block_copy_0, 
                               __main_block_dispose_0
                               };
Copy the code

Note that variables with __block added become structs

__Block_byref_block_val_0structure

// block_val generates a structure
struct __Block_byref_block_val_0 {
  void *__isa; // The specification becomes an object
__Block_byref_block_val_0 *__forwarding;
 int __flags;
 int __size;
 int block_val;
};
Copy the code

__Block_byref_instance_val_1structure

// __block decorates instance_val
struct __Block_byref_instance_val_1 {
  void *__isa;
__Block_byref_instance_val_1 *__forwarding;
 int __flags;
 int __size;
 void (*__Block_byref_id_object_copy)(void*, void*);
 void (*__Block_byref_id_object_dispose)(void*);
 NSObject *instance_val;
};
Copy the code

The __block variables __Block_byref_block_val_0 and __Block_byref_instance_val_1 are not in the Block’s __main_block_IMPL_0 structure, This is done so that __block variables can be used in multiple blocks

Intercept variable type

  • A local variable

    • Basic data types
      • The value is directly intercepted and cannot be modified
    • Object type
      • Intercepted along with the object ownership modifier
  • Static local variable

    • Captured in pointer form, block can be overwritten directly inside
  • The global variable

    • Block can be overwritten directly without interception
  • Static global variable

    • Block can be overwritten directly without interception
  • Static local variables, global variables, static global variables do not need to use the __block modifier

  • Variables of __block modified basic data types become objects (see __Block_byref_block_val_0,__Block_byref_instance_val_1)

When does a Block on the stack copy to the heap

  • Call of the Blockcopymethods
  • Block as a function return value
  • Copy the Block to the attach__strongThe modifieridType of a class or Block type
  • When a method hits a Cocoa framework method that contains a usingBlock or an API pass Block at Grand Central Dispatch

When using a __block variable in multiple blocks, since all blocks are first configured on the stack, the __block variable is also configured on the stack. When any Block is copied from the stack to the heap, the __block variable is copied from the stack to the heap and held by the Block. When the remaining blocks are copied from the stack to the heap, the copied Block holds the __block variable and increases the reference count of the __block variable

__forwardingPointer to the

  • Block on the stack__blockOf a variable structure__forwardingThe pointer points to itself
  • Stack Block after the copy operation, generated a stack Block, stack Block__blockOf a variable structure__forwardingPointer to heap Block__blockThe structure of a variable, the block on the heap__blockOf a variable structure__forwardingThe pointer points to itself
    • Through this function, both in Block syntax, Block syntax outside of use__blockVariable, or__blockVariables are configured on the stack or heap,Can access the same one without any problems__blockvariable

If there is a mistake, please indicate the source