Objective-c Block method

Source: Internet
Author: User

What is the meaning of block, features and so on, these things are really too complex, here is simply a summary of the block memory management. And it's only part of the objective-c.

Block Memory

Block memory management, should be the most headache, use this example from WWDC to explain it.

When the program runs here, there are shared variables and captured variables in the stack space.

As you can see here, the __block variable starts on the stack.

When the program runs here, there are shared variables, captured variables, and block1 in the stack space.

As you can see here, the variable of block type is also on the stack at the beginning.

When the program runs here, there are shared variables, captured variables, and block1 in the stack space.

It is worth noting that when we directly modify the captured variable on the stack, the captured variable in Block1 is still the original value of 10. In fact, from the const we can see that the captured variable in Block1 is not modifiable and is a const copy of the original variable from the stack. The captured variable accessed in Block1 is a const copy, that is, captured = 10 in Block1, instead of the value 20 on the original stack. Of course, in Block1, we cannot modify the captured variable.

Copy Block

Blocks are on a stack at the outset, for reasons of efficiency, but sometimes it is necessary for the Block's life cycle to be longer than the first stack, when we copy the block to the heap.

When the program finishes executing block2 = [block1 copy], the __block type variable shared is copied to the heap, and it is clear that the shared variable needs to be share by block and Block2 (and of course the stack is shared). The Block2 is moved into the heap, and it is likely that the life cycle will be in the stack, so gkfx is copied into the heap. The captured in Block2 is also copied into the heap.

When the program finishes executing BLOCK3 = [Block2 copy], what we see is that Block2 and Block3 are actually pointing to the same piece of memory space. In fact, the reference count is saved in the data structure of the block, and for copy to block in the heap, the behavior is the same as the normal object retain, which makes the reference count +1. So what happens if we do [block retain]? Nothing actually happened, at least in the current runtime version. Because the retain, not only the reference count +1, but also the return value of the retain, must be the same as the address of the return call object, and the address of the block is likely to change (stack or heap), so, here retain behavior is almost ignored.

When the block variable in the heap is destroyed prior to the stack, such as calling [Block2 release]; [Block2,block3 in Block3 Release];,heap is destroyed because the reference count is 0, and the __block variable is still in the heap because the stack is used, and block1 is used.

When the block variable in the heap is later than the stack, it is clear that the stack is cleared and there is nothing in the function.

Finally, when Block2 and Block3 are all release. Revert to the original state

Block details

When we write a block literal expression

^ {printf ("Hello world\n");}
In fact, the compiler generated the following structure for us
struct __block_literal_1 {
    void *isa;
    int flags;
    
    void (*invoke) (struct __block_literal_1 *);
    struct __block_descriptor_1 *descriptor;
};void __block_invoke_1 (struct __block_literal_1 *_block) {
    printf ("Hello world\n");
}static struct __block_descriptor_1 {
    unsigned long int reserved;
    unsigned long int block_size;
} __block_descriptor_1 = {0, sizeof (struct __block_literal_1)}; When block literal expression is used, __block_literal_1 is initialized to: struct __block_literal_1 _block_literal = {
    &_nsconcretestackblock,
    (1<<29), <uninitialized>
    __block_invoke_1,
    &__block_descriptor_1
   };

Next example

int x = 10;
void (^VV) (void) = ^{printf ("x is%d\n", x);};
x = 11;
VV ();
The compiler will generate the following structure
struct __block_literal_2{
    void *isa;
    int flags;
    int reserved;
    void (*invoke) (struct __block_literal_2 *);
    struct __block_descriptor_2 *descriptor;
    const int x;
};
void __block_invoke_2 (struct __block_literal_2 *_block) {
    printf ("X is%d\n", _block->x);
}
void struct __block_descriptor_2{
    unsigned long int reserved;
    unsigned long int block_size;
}__block_descriptor_2 = {0, sizeof (struct __block_literal_2)};
struct __block_literal_2 __block_literal_2 = {
    &nsconcretestackblock,
    (1<<29),
    __block_invoke_2,
    &__block_descriptor_2,
    X
};

The normal variable (int, char *) used in the block is imported as a const copy. Normal objects are retain. The __block type variable does nothing, just saves a pointer, and the global variable simply saves a simple pointer.

Of course, blocks might also be nested, so what would it look like? In fact, it's not complicated, it's just adding a copy function, and releasing the function, which is like the copy constructor of C + +, which is generated when necessary.

void (^existingblock) (void) = ...;
void (^VV) (void) = ^{existingblock ();};
VV ();
struct __block_literal_3{
    ...;//esisting block
};
struct __block_literal_4{
    void *isa;
    int flags;
    int reserved;
    void (*invoke) (struct __block_literal_4 *);
    struct __block_literal_3 *const existingblock;
};
void __block_invoke_4 (struct __block_literal_3 *__block) {
   __block->existingblock->invoke (__block->existingblock);
}
void __block_copy_4 (struct __block_literal_4 *dst, struct __block_literal_4 *src) {
     _block_copy_assign (&dst->existingblock, Src->existingblock, 0);
     _block_object_assign (&dst->existingblock, Src->existingblock, Block_field_is_block);
}
void __block_dispose_4 (struct __block_literal_4 *src) {
     Was _block_destroy
     _block_object_dispose (Src->existingblock, Block_field_is_block);
}
static struct __block_descriptor_4 {
    unsigned long int reserved;
    unsigned long int block_size;
    void (*copy_helper) (struct __block_literal_4 *dst, struct __block_literal_4 *src);
    void (*dispose_helper) (struct __block_literal_4 *);
} __block_descriptor_4 = {
    0,
    sizeof (struct __block_literal_4),
    __block_copy_4,
    __block_dispose_4,
};
Initialization
  struct __block_literal_4 _block_literal = {
    &_nsconcretestackblock,
    (1<<25) | (1<<29), <uninitialized>
    __block_invoke_4,
    & __block_descriptor_4
        Existingblock,
   };

__block Storage Variables

The __block variable is a very special type of data that has its own unique structure

struct _BLOCK_BYREF_XXXX {
    void *isa;
    struct _BLOCK_BYREF_XXXX *forwarding;
    int flags;   RefCount;
    int size;
    Helper functions called via Block_copy () and Block_release ()
    void (*byref_keep) (void  *dst, void *src);//generated when required
    void (*byref_dispose) (void *);//generated when needed
    typeof (Marked_variable) marked_variable;
};

Look at the use of __block type variables

int __block i = 10;
i = 11;
struct _block_byref_i {
    void *isa;
    struct _block_byref_i *forwarding;
    int flags;   RefCount;
    int size;
    int captured_i;
} i = {NULL, &i, 0, sizeof (struct _block_byref_i), 10};
I.forwarding->captured_i = 11;

Obviously, when the __block type variable is added to the block, the copy function of the nested block also increases the copy of the __block variable.

__block void (Voidblock) (void) = Blocka;
Voidblock = blockb;
struct _block_byref_voidblock {
    void *isa;
    struct _block_byref_voidblock *forwarding;
    int flags;   RefCount;
    int size;
    void (*byref_keep) (struct _block_byref_voidblock *dst, struct _block_byref_voidblock *src);
    void (*byref_dispose) (struct _block_byref_voidblock *);
    void (^captured_voidblock) (void);
};
void _block_byref_keep_helper (struct _block_byref_voidblock *dst, struct _block_byref_voidblock *src) {
    _block_copy_assign (&dst->captured_voidblock, Src->captured_voidblock, 0);
    _block_object_assign (&dst->captured_voidblock, Src->captured_voidblock, BLOCK_FIELD_IS_BLOCK | Block_byref_caller);
}
void _block_byref_dispose_helper (struct _block_byref_voidblock *param) {
    _block_destroy (param->captured_voidblock, 0);
    _block_object_dispose (Param->captured_voidblock, Block_field_is_block | Block_byref_caller)}
struct _block_byref_voidblock Voidblock = {(. forwarding=&voidblock,. flags= (1<<25),. size=sizeof (struct _ Block_byref_voidblock *),
      . Byref_keep=_block_byref_keep_helper,. Byref_dispose=_block_byref_dispose_helper,
      . Captured_voidblock=blocka)};
Voidblock.forwarding->captured_voidblock = blockb;

block, the introduction of the __block what would be the case

int __block i = 2;
Functioncall (^{i = 10;});
struct _block_byref_i {
    void *isa;  Set to NULL
    struct _block_byref_voidblock *forwarding;
    int flags;   RefCount;
    int size;
    void (*byref_keep) (struct _block_byref_i *dst, struct _block_byref_i *src);
    void (*byref_dispose) (struct _block_byref_i *);
    int captured_i;
};
struct __block_literal_5 {
    void *isa;
    int flags;
    
    void (*invoke) (struct __block_literal_5 *);
    struct __block_descriptor_5 *descriptor;
    struct _block_byref_i *i_holder;
};
void __block_invoke_5 (struct __block_literal_5 *_block) {
   _block->i_holder->forwarding->captured_i = 10;
}
void __block_copy_5 (struct __block_literal_5 *dst, struct __block_literal_5 *src) {
     _block_object_assign (&dst->i_holder, Src->i_holder, Block_field_is_byref | Block_byref_caller);
}
void __block_dispose_5 (struct __block_literal_5 *src) {
     _block_object_dispose (Src->i_holder, Block_field_is_byref | Block_byref_caller);
}
static struct __block_descriptor_5 {
    unsigned long int reserved;
    unsigned long int block_size;
    void (*copy_helper) (struct __block_literal_5 *dst, struct __block_literal_5 *src);
    void (*dispose_helper) (struct __block_literal_5 *);
} __block_descriptor_5 = {0, sizeof (struct __block_literal_5) __block_copy_5, __block_dispose_5};
struct _block_byref_i i = {(. forwarding=&i,. flags=0,. size=sizeof (struct _block_byref_i))};
struct __block_literal_5 _block_literal = {
    &_nsconcretestackblock,
    (1<<25) | (1<<29), <uninitialized>
    __block_invoke_5,
    &__block_descriptor_5,
        2,
   };

The above content from http://www.cnblogs.com/studentdeng/archive/2012/02/03/2336863.html will not boot the boy wrote, for block think this write is very detailed, so direct reference to!

Objective-c Block method

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.