Block yes iOS A special data structure in development , It can hold a piece of code , Call... In the right place , Have a brief introduction to grammar 、 Easy callback 、 The programming idea is clear 、 High efficiency of execution , Loved by many apes . however Block In use , If the Block I don't understand very well , It's easy to see Cycle Retain The problem of . This paper mainly from ARC Analyze it in mode Block The underlying implementation of , as well as Block Three types of ( Stack 、 Pile up 、 overall situation ) The difference between .

One 、Block Definition

1. Block Define and use

 return type (^block Variable name )( Parameter list ) = ^ return type ( Parameter list ) {
}; // call Block Saved code
block Variable name ( Actual parameters );

2. The format used in the project

In the project , It's usually redefined block An alias for the type of , And then use aliases to define block The type of

// Definition block type 
typedef void (^Block)(int); // Definition block
Block block = ^(int a){}; // call block
block(3);

Two 、Block Underlying implementation

block The underlying implementation of is the structure , Similar to the underlying implementation of a class , There are isa The pointer , You can put block As an object . Next, create a console program , Come and see block The underlying implementation of

1. block Memory structure

block Memory structure diagram of

Block_layout The meaning of structural members is as follows :

  • isa: A pointer to the class to which it belongs , That is to say block The type of
  • flags: Flag variable , In the realization of block You'll use
  • Reserved: Keep variables
  • invoke: block Pointer to the function called at execution time ,block The internal execution code is in this function
  • descriptor: block Detailed description of , contain copy/dispose function , Handle block Use... When referring to external variables
  • variables: block Variables out of range , If block No external variables were called , The variable doesn't exist

Block_descriptor The meaning of structural members is as follows :

  • reserved: Keep variables
  • size: block The memory size of
  • copy: Copy block Middle quilt __block Modifying external variables
  • dispose: and copy Method configuration application , To release resources

The specific implementation code is as follows ( Code from Block_private.h):

enum {
BLOCK_REFCOUNT_MASK = (0xffff),
BLOCK_NEEDS_FREE = (1 << 24),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_DESCRIPTOR = (1 << 29)
}; /* Revised new layout. */
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
}; struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};

2. establish block

int main(int argc, const char * argv[]) {
@autoreleasepool { // Simplest block
^{ };
}
return 0;
}

3. Transformation structure

utilize clang hold *.m File to *.cpp file , You can see that block The underlying implementation of

$ clang -rewrite-objc main.m

The converted code :

struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
}; struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
} static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
(void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA);
}
return 0;
}

As you can see from the code ,__main_block_impl_0 Namely block Of C++ Realization ( The last one _0 Representative is main Number one of them block),__main_block_func_0 yes block Code block for ,__main_block_desc_0 yes block Description of ,__block_impl yes block The definition of .

__block_impl The meaning of members is as follows :

  • isa: A pointer to the class to which it belongs , That is to say block The type of
  • flags, Flag variable , In the realization of block You'll use
  • Reserved, Keep variables
  • FuncPtr,block Pointer to the function called at execution time

__main_block_impl_0 Explain the following :

  • impl: block object
  • Desc: block Description of the object

among ,__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) This is an explicit constructor ,flags The default value is 0, The body of the function is as follows :

__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}

It can be seen that :

  • __main_block_impl_0 Of isa The pointer points to _NSConcreteStackBlock, All the parts block It's all created at the door of the stack
  • from main Function , __main_block_impl_0 Of FuncPtr Points to the function __main_block_func_0
  • __main_block_impl_0 Of Desc It also points to the definition __main_block_desc_0 It was created when __main_block_desc_0_DATA, among Block_size Recorded block Structure size and other information

__main_block_desc_0 The meaning of members is as follows :

  • reserved: Keep variables
  • Block_size: block Memory size ,sizeof(struct __main_block_impl_0)

3、 ... and 、Block type

block There are three types :

  • _NSConcreteGlobalBlock: Stored in the global data area
  • _NSConcreteStackBlock: Store in stack area
  • _NSConcreteMallocBlock: Stored in the heap

APUE The process virtual memory segment distribution is as follows :

among ,_NSConcreteGlobalBlock and _NSConcreteStackBlock It can be created by a program , and _NSConcreteMallocBlock Cannot be created by the program , Only by _NSConcreteStackBlock By copying .

1. overall situation block and Stack block

The test code is as follows :

void (^globalBlock)() = ^{
};
int main(int argc, const char * argv[]) {
@autoreleasepool { void (^stackBlock1)() = ^{ };
}
return 0;
}

clang The converted code is as follows :

// globalBlock
struct __globalBlock_block_impl_0 {
...
__globalBlock_block_impl_0(void *fp, struct __globalBlock_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteGlobalBlock;
...
}
};
... // stackBlock
struct __main_block_impl_0 {
...
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
...
}
};
...
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
void (*stackBlock)() = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA);
}
return 0;
}

It can be seen that , globalBlock Of isa Yes _NSConcreteGlobalBlock, That is to create... In the global area , At compile time, the specific code is in the code segment ,block Variables are stored in the global data area ; and stackBlock Of isa It points to _NSConcreteStackBlock, Indicates that... Is created in the stack area .

2. Capture external parameters on stack block The influence of structure

Because of the heap area block It's the stack area block Transformed into , So the main analysis stack area block How to convert to heap area block.

Capture local non static variables

Code :

 int a = 0;
^{a;};

After the transformation :

struct __Person__test_block_impl_0 {
...
int a;
// a(_a) Is the parameter list initialization form of the constructor , amount to a = _a. from _I_Person_test see , What's coming in is a
__Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
...
}
}; static void _I_Person_test(Person * self, SEL _cmd) {
int a;
(void (*)())&__Person__test_block_impl_0((void *)__Person__test_block_func_0, &__Person__test_block_desc_0_DATA, a);
}

You can see ,block References to stack variables are just value passing , because block Internal variables a and External variables a Not in the same scope , So in block Internal variables can't be a As left value (left-value), Because assignment doesn't make sense . therefore , If the following code appears , The compiler will prompt for errors :

a = 10;

Capture local static variables

Code :

 static int a;
^{
a = 10;
};

After the transformation :

struct __Person__test_block_impl_0 {
...
int *a;
__Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, int *_a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
...
}
};
static void __Person__test_block_func_0(struct __Person__test_block_impl_0 *__cself) {
int *a = __cself->a; // bound by copy
// Here, through local static variables a To modify it
(*a) = 10;
} static void _I_Person_test(Person * self, SEL _cmd) {
static int a;
// Pass in a The address of
(void (*)())&__Person__test_block_impl_0((void *)__Person__test_block_func_0, &__Person__test_block_desc_0_DATA, &a);
}

Since local static variables are also stored in the static data area , It's the same as the program Life cycle , But its scope is limited to the functions that define it , All in block It's through Address To visit .

Capture global variables

Code :

// Global static 
static int a;
// overall situation
int b;
- (void)test
{ ^{
a = 10;
b = 10;
};
}

After the transformation :

static int a;
int b; static void __Person__test_block_func_0(struct __Person__test_block_impl_0 *__cself) { a = 10;
b = 10;
} static void _I_Person_test(Person * self, SEL _cmd) { (void (*)())&__Person__test_block_impl_0((void *)__Person__test_block_func_0, &__Person__test_block_desc_0_DATA);
}

It can be seen that , Because global variables are in the static data area , It won't be destroyed until the end of the program , therefore block Directly access the corresponding variable , And not in Persontest_block_impl_0 In the structure, a place is reserved for variables .

Capture variables of objects

Code :

@interface Person()
{
int _a;
} @end @implementation Person - (void)test
{
void (^block)() = ^{
_a;
};
} @end

After the transformation :

struct __Person__test_block_impl_0 {
...
Person *self;
__Person__test_block_impl_0(void *fp, struct __Person__test_block_desc_0 *desc, Person *_self, int flags=0) : self(_self) {
impl.isa = &_NSConcreteStackBlock;
...
}
}; static void __Person__test_block_func_0(struct __Person__test_block_impl_0 *__cself) {
Person *self = __cself->self; // bound by copy (*(int *)((char *)self + OBJC_IVAR_$_Person$_a));
} static void _I_Person_test(Person * self, SEL _cmd) {
void (*block)() = ((void (*)())&__Person__test_block_impl_0((void *)__Person__test_block_func_0, &__Person__test_block_desc_0_DATA, self, 570425344));
}

You can see , Even if block Just variables that reference objects , But the underlying layer still refers to the object itself self, This and direct use self.a The problem with the generated circular references is the same . therefore , To be in block Use weak references to objects inside , Can solve the problem of circular reference . also , The variable a My visit is also through self My address plus a The form of the offset of .

Capture __block The basic variable of modification

Code :

 __block int a;
^{
a = 10;
};

After the transformation :

struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
int a;
}; struct __main_block_impl_0 {
...
__Block_byref_a_0 *a; // by ref
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_a_0 *_a, int flags=0) : a(_a->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
...
}
}; static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
__Block_byref_a_0 *a = __cself->a; // bound by ref
(a->__forwarding->a) = 10;
} static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 8/*BLOCK_FIELD_IS_BYREF*/);} static struct __main_block_desc_0 {
...
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}; int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; __attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 0, sizeof(__Block_byref_a_0), 1}; ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344));
}
return 0;
}

You can see , By __block The modified variable is encapsulated as an object , The type is __Block_byref_a_0, And then put &a Passed to as a parameter block.

__Block_byref_a_0 The meaning of members is as follows :

  • __isa: A pointer to the class to which it belongs , Is initialized to (void*)0
  • __forwarding: Point to the copy of the object in the heap
  • __flags: Flag variable , In the realization of block You'll use
  • __size: Object's memory size
  • a: Variables of primitive type

among ,isa__flags and __size The meaning of is similar to before , and __forwarding It's used to point to a copy of an object in the heap ,runtime.c There's a source code description in it :

static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
...
struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
// Copied from the heap forwarding Point to itself
copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
// In the stack forwarding Point to the copy in the heap
src->forwarding = copy; // patch stack to point to heap copy
copy->size = src->size;
...
}

This is to make sure that block Inside or block Variables are followed by variables a The interview of , All are direct access to objects in the heap , Instead of variables on the stack . meanwhile , stay block When copying to the heap , What it captures is __block Modified local base types are also copied to the heap ( What is copied is the encapsulated object ), So there will be copy and dispose Processing function .

Block_byref The structure of is defined in Block_private.h It's in the file :

struct Block_byref {
void *isa;
struct Block_byref *forwarding;
int flags; /* refcount; */
int size;
void (*byref_keep)(struct Block_byref *dst, struct Block_byref *src);
void (*byref_destroy)(struct Block_byref *);
/* long shared[0]; */
}; // flags/_flags type
enum {
/* See function implementation for a more complete description of these fields and combinations */
// It's an object
BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), block, ... */
// It's a block
BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
// By __block Decorated variable
BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block variable */
// By __weak Decorated variable , It can only be aided copy Function USES
BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy helpers */
// block Auxiliary function call ( Tell the internal implementation not to retain perhaps copy)
BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose support routines. */
};

You can see ,Block_byref and __Block_byref_a_0 Before 4 Members of the same type , Can transform each other .

** copy function

copy The implementation function of is _Block_object_assign, It depends on the flags To determine if you need to copy , Or just an assignment , Function implementation in runtime.c in :

// _Block_object_assign Source code 
void _Block_object_assign(void *destAddr, const void *object, const int flags) {
...
else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) {
// copying a __block reference from the stack Block to the heap
// flags will indicate if it holds a __weak reference and needs a special isa
_Block_byref_assign_copy(destAddr, object, flags);
}
...
} // _Block_byref_assign_copy Source code
static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
// Here because of the front 4 The memory distribution of each member is the same , So after the direct conversion , Use Block_byref Member variable name of , Can access __Block_byref_a_0 In front of 4 Members
struct Block_byref **destp = (struct Block_byref **)dest;
struct Block_byref *src = (struct Block_byref *)arg;
...
else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
// from main Function pair __Block_byref_a_0 The initialization , You can see that initialization will flags The assignment is 0
// This is the first copy , Will copy , And modify the original flags Value
// static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
// It can be seen that , After copying , Will be incorporated into BLOCK_NEEDS_FREE, hinder 2 yes block Initial reference count for
...
copy->flags = src->flags | _Byref_flag_initial_value;
...
}
// Has been copied to the heap , Just increase the reference count
else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
latching_incr_int(&src->forwarding->flags);
}
// Normal assignment , The bottom of it is *destptr = value; This expression
_Block_assign(src->forwarding, (void **)destp);
}

The main operations are in the code comments , On the whole ,__block The basic types of modifiers are wrapped as objects , And only in the beginning block Copy once while copying , The subsequent copy will only increase the reference count of this capture variable .

** dispose function

dispose The implementation function of is _Block_object_dispose, The code can still be in runtime.c in :

void _Block_object_dispose(const void *object, const int flags) {
//printf("_Block_object_dispose(%p, %x)\n", object, flags);
if (flags & BLOCK_FIELD_IS_BYREF) {
// get rid of the __block data structure held in a Block
_Block_byref_release(object);
}
...
} // Old compiler SPI
static void _Block_byref_release(const void *arg) {
struct Block_byref *shared_struct = (struct Block_byref *)arg;
int refcount; // dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
shared_struct = shared_struct->forwarding; ...
refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
...
else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
...
}
}

You can see , By __block Modified variables , Release with latching_decr_int Minus the reference count , Until the count is 0, Just release and change the object ; And ordinary objects 、block, Just release it and destroy it .

Capture did not __block Decorated object

Code :

 NSObject *a = [[NSObject alloc] init];
Block block = ^ {
a;
};

Some of the results are as follows :

static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
NSObject *a = __cself->a; // bound by copy
a;
} static void __main_block_copy_0(struct __main_block_impl_0*dst, struct __main_block_impl_0*src) {_Block_object_assign((void*)&dst->a, (void*)src->a, 3/*BLOCK_FIELD_IS_OBJECT*/);} static void __main_block_dispose_0(struct __main_block_impl_0*src) {_Block_object_dispose((void*)src->a, 3/*BLOCK_FIELD_IS_OBJECT*/);} int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
...
Block block = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, a, 570425344));
}
return 0;
}

The object is not __block When decorating , It didn't produce __Block_byref_a_0 Structure , Just change the flag bit to BLOCK_FIELD_IS_OBJECT. And in the _Block_object_assign The corresponding branch code in is as follows :

...
else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
_Block_retain_object(object);
_Block_assign((void *)object, destAddr);
}
...

You can see ,block Replication time , Meeting retain Capture objects , To increase its reference count .

There are __block Decorated object

Code :

 __block NSObject *a = [[NSObject alloc] init];
Block block = ^ {
a;
};

Some of the results are as follows :

struct __Block_byref_a_0 {
void *__isa;
__Block_byref_a_0 *__forwarding;
int __flags;
int __size;
void (*__Block_byref_id_object_copy)(void*, void*);
void (*__Block_byref_id_object_dispose)(void*);
NSObject *a;
};
int main(int argc, const char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
attribute__((__blocks__(byref))) __Block_byref_a_0 a = {(void*)0,(__Block_byref_a_0 *)&a, 33554432, sizeof(__Block_byref_a_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131,....};
Block block = (void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_a_0 *)&a, 570425344);
} // Following 40 Express __Block_byref_a_0 object a The displacement of (4 A pointer to the (32 byte )+2 individual int Variable (8 byte )=40 byte )
static void __Block_byref_id_object_copy_131(void *dst, void *src) {
_Block_object_assign((char*)dst + 40, *(void * *) ((char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
_Block_object_dispose(*(void * *) ((char*)src + 40), 131);
}

You can see , For the object , Processing increased __Block_byref_a_0 Outside , Two additional auxiliary functions are added __Block_byref_id_object_copy__Block_byref_id_object_dispose, To realize the management of object memory . The last parameter of both 131 Express BLOCK_BYREF_CALLER|BLOCK_FIELD_IS_OBJECT,BLOCK_BYREF_CALLER Indicates that it is not correct in the internal implementation a Object to carry out retain or copy; The following is a _Block_object_assign Part of the code for the function :

if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
...
else {
// do *not* retain or *copy* __block variables whatever they are
_Block_assign((void *)object, destAddr);
}
}

_Block_byref_assign_copy The following code of the function will be used for the auxiliary function above __Block_byref_id_object_copy_131 To call ;570425344 Express BLOCK_HAS_COPY_DISPOSE | BLOCK_HAS_DESCRIPTOR, namely (1<<25 | 1<<29),_Block_byref_assign_copy Part of the code for the function :

if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
// Trust copy helper to copy everything of interest
// If more than one field shows up in a byref block this is wrong XXX
copy->byref_keep = src->byref_keep;
copy->byref_destroy = src->byref_destroy;
(*src->byref_keep)(copy, src);
}

Four 、ARC in block Characteristics of our work

stay ARC In mode , Pass between stacks block when , No manual operation required copy In the stack block, You can make block Normal work . The main reason is ARC Yes, in the stack block Automatic execution copy, take _NSConcreteStackBlock Type of block Transformed into _NSConcreteMallocBlock Type of block.

1. block, Non functional parameters

Code :

 int i = 10;
void (^block)() = ^{i;}; __unsafe_unretained void (^weakBlock)() = ^{i;}; void (^stackBlock)() = ^{}; NSLog(@"%@", ^{i;}); NSLog(@"%@", block); NSLog(@"%@", weakBlock); NSLog(@"%@", stackBlock); /* ARC
<__NSStackBlock__: 0x7fff5fbff708>
<__NSMallocBlock__: 0x100300000>
<__NSStackBlock__: 0x7fff5fbff738>
<__NSGlobalBlock__: 0x100001110>
*/ /* MRC
<__NSStackBlock__: 0x7fff5fbff6e0>
<__NSStackBlock__: 0x7fff5fbff740>
<__NSStackBlock__: 0x7fff5fbff710>
<__NSGlobalBlock__: 0x1000010e0>*/

It can be seen from the printed results that ,ARC In mode ,block Only external variables are referenced , And it's strongly quoted , Will be copied to the heap ; Only external variables are referenced , Or weak references are only created on the stack ; If there is no reference to an external variable , Whether or not strongly cited , Will be transformed into a global block, in other words , At compile time , This block All the content of is already in Code segment Generated in the .

2. block, Pass as a parameter

Code

typedef void (^Block)();
NSMutableArray *arrays;
void testBlock() {
int a = 5; [arrays addObject:^{
NSLog(@"%d", a);
}];
} int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here.. arrays = @[].mutableCopy; testBlock(); Block block = [arrays firstObject]; NSLog(@"%@", block); /* ARC
* <__NSMallocBlock__: 0x1006034c0>
*/ /* MRC
* collapse , Wild pointer
*/
}
return 0;
}

It can be seen that ,ARC In mode , Stack area block It's copied to the heap , stay testBlock After the function is finished, you can still access ; and MRC In mode , Because we didn't do it manually [block copy] to block Copy to the heap , As the function life cycle ends ,block Be destroyed , Wild pointer error while accessing , But if you put testBlock Function block Delete the print statement :

NSLog(@"%d", a);

that ,block It becomes global , stay MRC In mode , There will be no error accessing again .


Reference article

http://www.jianshu.com/p/51d04b7639f1

http://www.jianshu.com/p/aff2cad778c0

http://www.galloway.me.uk/2013/05/a-look-inside-blocks-episode-3-block-copy/

runtime.c

Block.private.h

iOS - Block More articles on bottom layer parsing

  1. 【iOS Singleton design pattern 】 Bottom layer analysis and application

    [iOS Singleton design pattern ] Bottom layer analysis and application One . Explanation of single example design terms : ( Official explanation ) The singleton pattern ensures that there is only one instance of a class , Provide this instance by yourself and provide this instance to the whole system .( Image metaphor ) Program — company   A single example - management ...

  2. iOS Technology : From using to understanding block Underlying principle ( Two )

    block The essence preface In the last article, it is mainly through simple demo It shows block Usage scenarios of , This article will be based on the previous article iOS Technology : From using to understanding block Underlying principle ( One ) Learn more block The underlying implementation principle . bloc ...

  3. iOS OC Language : Block Underlying implementation principle

    Let's briefly introduce BlockBlock What is it? ? The type Apple recommends , Efficient , Save the code in the run . To encapsulate and save code , It's kind of like a function ,Block It can be executed at any time . Block And the similarity of functions :(1) You can save the code (2) ...

  4. iOS block The underlying implementation of

    Actually swift The closure of and OC Of block It's the same thing , Learned to block, you swift The closure inside will be self-taught . Reference resources :http://www.jianshu.com/p/e23078c11518 ht ...

  5. iOS OC Language : Block Underlying implementation principle ( Reprint )

    author :Liwjing Address :http://www.jianshu.com/users/8df89a9d8380/latest_articles Let's briefly introduce Block Block What is it? ? Apple recommends ...

  6. 【iOS series 】-iOS Multithread parsing of

    [iOS series ]-iOS Multithread parsing of iOS Multithreading implementation technology of : 1:GCD -- Grand Central Dispatch Is based on C The bottom of the language API use Block Define the task , It's very flexible and convenient to use Provide ...

  7. iOS Block The interface transfers the value backward

    In the last blog <iOS Block brief introduction >  in , It focuses on the analysis of  iOS Block And so on , This article will focus on their application in development . Block yes iOS4.0+ and Mac OS X 10.6+ Introduced right C ...

  8. iOS block Starting from scratch

    iOS block Starting from scratch stay iOS4.0 after ,block Born in the sky , It encapsulates a piece of code and treats it as a variable , adopt block() Call back in the same way . block Structure Let's take a look at a simple piece of code : void ...

  9. iOS block Usage of

    Learning objectives in this chapter : 1. Understand what block. 2. understand block How to use . Block yes iOS stay 4.0 After that, the new program syntax , Strictly speaking block The concept of basic programming is not the scope of basic programming , It's not very good for beginners ...

Random recommendation

  1. modify git remote url

    $ ssh -v wangz@gitlab.alibaxx-inc.com $ git remote ali set-url git@gitlab.alibaxx-inc.com:youk-aaa/x ...

  2. Java The role of the reflex mechanism

    Suppose we had two programmers , When a programmer writes a program , You need to use the class written by the second programmer , But the second programmer didn't finish the class he wrote . Can the code of the first programmer be compiled ? This can't be compiled . utilize Java The mechanism of reflection , Can ...

  3. HDU 5593 ZYB&#39;s Tree Tree form dp

    Topic link : http://acm.hdu.edu.cn/showproblem.php?pid=5593 The question : http://bestcoder.hdu.edu.cn/contests/contes ...

  4. ( turn ) class II

    Overloading operators   Classes, essentially, define new types to be used in C++ code. And types in ...

  5. await and async More understanding

    Recently, many netizens mentioned await and async, ha-ha ,C# 5 Introduced grammar sugar . This grammar candy is not delicious , You can beat a bunch of buddies , There are also many netizens' arguments about this knowledge point on the Internet , There are right and wrong , Today, let's talk about this misunderstanding . stay ...

  6. UINavigationController appear nested push animation can result in corrupted navigation bar Error prompt for

    Today, in the process of testing , There is such a bug. There are two scenarios : ( Premise is :app Is based on UINavigationController Built ) 1. from Controller-A in push Come in B. stay B Click to return , return ...

  7. vue-cli Build the project npm run build How to run after the test to check the effect locally

    problem : Namely bulid After packing , I want to see the effect , I can't see it here .... I saw one on the Internet ....   More specifically in : http://www.dabaipm.cn/static/frontend/346.htm ...

  8. combotree Summary of ( This is good )

    1: There's a demand for this recently , Namely ext Under the combo It's a tree , There are many examples on the Internet , The packaging is also very good , Basically, it can meet the requirement that the desired tree appears under the drop-down box , But my usage is, for example, when users edit , To automatically assign the selected value to the drop-down list ...

  9. vs2017 Start debugging , Click browser or enter and the browser will flash back , Debug interrupt

    vs2017 After starting debugging , Browser running , Click on the address bar and just input a few characters ,mmmmm It's back ! What's the situation ? Test it , Switch to another browser to debug , Once in a while there's no problem , But the next day ...... Just for a second So the browser ——ww ...

  10. python--- Iterators and generators ( One )

    Iterators and generators iterator Iteration is Python One of the most powerful features , Is a way to access collection elements .. An iterator is an object that remembers the traversal location . The iterator object is accessed from the first element of the collection , Until all elements are accessed . iteration ...