doubt

Block is usually used to capture object variables, so the capture of object variables is the same as the basic data type variables? When an object type is accessed in a block, when is the object destroyed?

typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Block block;
        {
            Person *person = [[Person alloc] init];
            person.age = 10;
            
            block = ^{
                NSLog(@"-- -- -- -- -- - the block internal % d",person.age); }; } NSLog(@"-- -- -- -- -- -- -- --");
        // Person --- dealloc
    }
    return 0;
}
Copy the code

After the brace completes, the person is not released. , person is the auto variable, and the variable in the passed block is also Person, i.e. the block has a strong reference to Person, so the person will not be destroyed if the block is not destroyed.

Looking at the source code does

Move the above code to the MRC environment, where the person is freed even though the block is still in place. Because MRC blocks are on the stack, blocks on the stack do not strongly reference the person outside.

typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Block block;
        {
            Person *person = [[Person alloc] init];
            person.age = 10;
            
            block = ^{
                NSLog(@"-- -- -- -- -- - the block internal % d",person.age);
            };
            [person release];
            // Person --- dealloc
        }
        NSLog(@"-- -- -- -- -- -- -- --");
        
    }
    return0; } Block calls copy and the person is not released. block = [^{ NSLog(@"-- -- -- -- -- - the block internal % d",person.age);
} copy];


Copy the code

The block in the stack space will be copied to the heap and the person will not be released. Therefore, the block in the stack space may be retained to ensure that the person will not be destroyed. Blocks in heap space also release the objects they hold after they destroy themselves.

That is, blocks in stack space do not strongly reference objects, and blocks in heap space have the ability to hold externally called objects, that is, to strongly reference objects or remove strong references.

__weak

With __weak added, the person is destroyed after the scope completes execution.

typedef void (^Block)(void);

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Block block;
        {
            Person *person = [[Person alloc] init];
            person.age = 10;
            
            __weak Person *waekPerson = person;
            block = ^{
                NSLog(@"-- -- -- -- -- - the block internal % d",waekPerson.age);
            };
        }
        NSLog(@"-- -- -- -- -- -- -- --");
    }
    return 0;
}

Copy the code

Convert the code to c++ to see the differences. -fobjc-arc-fobjc-Runtime =ios-8.0.0 -fobjc-runtime=ios-8.0.0 -fobjc-runtime=ios-8.0.0

Xcrun-sdk iphoneOS clang-arch arm64-rewrite-fobjc-arc-fobjc-Runtime =ios-8.0.0 main.m

__main_block_copy_0 and __main_block_dispose_0

When the object type variables are captured in the block, we find that the __main_block_IMPL_0 description structure __main_block_desc_0 has two more parameters copy and dispose function, check the source code:

Both copy and dispose pass in the __main_block_IMPL_0 structure itself.

Copy is essentially the __main_block_copy_0 function. The __main_block_copy_0 function internally calls the _Block_object_assign function. The _Block_object_assign function is passed the address of the person object. The Person object, and 8.

Dispose is essentially the __main_block_dispose_0 function. The __main_block_dispose_0 function calls the _Block_object_dispose function. The _Block_object_dispose function takes the person object as arguments, along with 8.

_Block_object_assign function call timing and function

When a block copies, the __main_block_copy_0 function inside __main_block_DESc_0 is automatically called, and the _Block_object_assign function inside __main_block_copy_0 is called.

The _Block_object_assign function automatically makes a strong or weak reference to a Person object depending on what type of pointer person is inside the __main_block_IMPL_0 structure. The __main_block_IMPL_0 person pointer is __strong, and the reference count is +1. If the __main_block_IMPL_0 person pointer is __strong, the reference count is +1. If the person pointer in the __main_block_IMPL_0 structure is of type __weak, it is a weak reference and the reference count remains the same. Time and effect of _Block_object_dispose function call

The __main_block_dispose_0 function in __main_block_DESc_0 is called automatically when a block is removed from the heap. The _Block_object_dispose function is called inside __main_block_dispose_0.

The _Block_object_dispose dispose dispose of the Person object, which is similar to release and disreferences the Person object, depending on the reference count of the person object.

conclusion

Once a variable captured in a block is of object type, __main_block_DESc_0 in the block structure produces two arguments copy and dispose. Because it's an object that a block wants to own, it needs to reference that object, which is memory management. As an example, when a block captures an object with an retarn function, it automatically generates copy and Dispose to manage its internal reference objects. When a block accesses the auto variable of the object type, there is no strong reference to Person inside the block if the block is on the stack. There is no strong reference to a variable inside the block structure, regardless of whether the variable is __strong or __weak. If the block is copied to the heap. Copy calls the _Block_object_assign function, and executes a strong or weak reference based on the __strong, __weak, and unsafe_unretained parameter of the auto variable. If a block is removed from the heap, The dispose function calls the _Block_object_dispose function, which automatically releases the referenced auto variable.Copy the code

doubt

When the person is destroyed

1.


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    Person *person = [[Person alloc] init];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"% @",person);
    });
    NSLog(@"touchBegin----------End");
}

Copy the code

2,

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    Person *person = [[Person alloc] init];
    
    __weak Person *waekP = person;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"% @",waekP);
    });
    NSLog(@"touchBegin----------End");
}

Copy the code

3,

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { Person *person = [[Person alloc] init]; __weak Person *waekP = person; Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(@)"weakP ----- %@",waekP);
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"person ----- %@",person);
        });
    });
    NSLog(@"touchBegin----------End");
}

Copy the code

4,

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { Person *person = [[Person alloc] init]; __weak Person *waekP = person; Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{NSLog(@)"person ----- %@",person);
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"weakP ----- %@",waekP);
        });
    });
    NSLog(@"touchBegin----------End");
}

Copy the code

Conclusion doubt

1. When a block is used as a method parameter in the GCD API, it automatically copies the object, so the block is in the heap and uses a strong reference to the Person object, so the copy function inside the block will strongly reference person. When the block is completed and needs to be destroyed, dispose is called to release the reference to the Person object. The person will be destroyed only when there is no strong pointer to it.

So: Destroy the Person object after 3 seconds

2. WaekP in the block is __weak, so the block copy function also weakly references Person. When the curly braces are completed, the person object with no strong pointer reference is freed. Therefore, block execution prints NULL.

So: Destroy the Person object immediately

The third one and the fourth one you can verify for yourself.