This is the 11th day of my participation in the August Wenwen Challenge.More challenges in August

Block type

MallocBlock: in the heap, with local variables or OC attributes inside the block and assigned to strongly referenced or copy-modified variables StackBlock: Blocks on the stack, like blocks on the heap, can use local variables or OC attributes internally, but cannot be assigned to strongly referenced or copy-modified variables

Here are three types of block creation that do not use external variables:

   void (^block)(void) = ^{ };
Copy the code

Local variables are used and strongly referenced:

   int a = 10;
   void (^block)(void) = ^ {NSLog(@" - %d",a);
   };
Copy the code

Local variables are used, but there is no strong reference:

   int a = 10;
   void (^ __weak block)(void) = ^ {NSLog(@"- %d",a);
   };
Copy the code

Block is a strong reference by default, pointing to^ {}Memory space.

Block captures external variables

- (void)blockDemo2{
    
    NSObject *objc = [NSObject new];
    NSLog(@"%ld".CFGetRetainCount((__bridge CFTypeRef)(objc))); / / 1
    
    void(^strongBlock)(void) = ^ {// This is actually strongBlock against objc so +1
        NSLog(@"---%ld".CFGetRetainCount((__bridge CFTypeRef)(objc)));
    };
    strongBlock();

    void(^ __weak weakBlock)(void) = ^ {/ / + 1
        NSLog(@"---%ld".CFGetRetainCount((__bridge CFTypeRef)(objc)));
    };
    weakBlock();
    
    void(^mallocBlock)(void) = [weakBlock copy];
    mallocBlock();
    
}
Copy the code

And finally, to the externalobjcWhat is the reference count?Analysis: The problem here is mainly instrongBlock()Here, we follow our common sensestrongBlockCapture objc so +1 should be 2, so why print 3? The reason herestrongBlockIs a heap block, it is copied from the stack to the heap, so here also +1, specific we below combined with the source codelibclosureAnalysis. So the topstrongBlock = __weak weakBlock + [weakBlock copy]

Block memory copy

- (void)blockDemo1{
    int a = 0;
    void(^ __weak weakBlock)(void) = ^ {NSLog(@"-----%d", a);
    };
    struct _LGBlock *blc = (__bridge struct _LGBlock *)weakBlock;
  
    // Depth copy
    id __strong strongBlock = weakBlock;
    blc->invoke = nil;
    void(^strongBlock1)(void) = strongBlock;
    strongBlock1();
}
Copy the code

The _LGBlock in this article is a custom block, and the focus here is on the memory copy of the block, so this detail can be ignored. Running the above code crashes. Because the current BLC ->invoke = nil, it is also verified that BLC and weakBlock point to the same piece of memory space, so when BLC is set to nil, it crashes. So how do we fix this? We can actually do this.

// Deep and shallow copy At this point, it is a heap area. Block value is the same as weakBlock, but it is a new memory address
id __strong strongBlock = [weakBlock copy];
Copy the code

Block stack releases the difference

- (void)blockDemo3{
    int a = 0;
    void(^ __weak weakBlock)(void) = nil;
    {
        void(^ __weak strongBlock)(void) = ^ {NSLog(@"---%d", a);
        };
        weakBlock = strongBlock;
        NSLog(@"---1");
    }
    weakBlock();
}
Copy the code

Stack area in code blockstrongBlockThe value is assigned to the stackweakBlock. What if we change it this way?

- (void)blockDemo3{
    int a = 0;
    void(^ __weak weakBlock)(void) = nil;
    {
        void(^strongBlock)(void) = ^ {NSLog(@"---%d", a);
        };
        weakBlock = strongBlock;
        NSLog(@"---1");
    }
    weakBlock();
}
Copy the code

Run at this point, the program crashed inweakBlock()here At this timestrongBlockIt’s a heap areablockPile, theblockAssigned toweakBlockTurn the Block into a heap areablock butstrongBlockIt’s released after it’s out of scope, so theta at this pointweakBlockThe address pointing to is also empty, so an error is reported. The main thing is to distinguish between areas of stack release.

Blocks are copied to the heap

  • manualcopy
  • blockAs a return value
  • Being strongly quoted orcopymodified
  • The system API containsusingBlock

Block loop reference

The following example creates a circular reference due to self -> block -> self.

    self.block = ^(void) {NSLog(@ "% @".self.name);
    };
    self.block();
Copy the code

__weak: self -> block -> weakSelf(nil)

    __weak typeof(self) weakSelf = self;
    self.block = ^(void) {NSLog(@ "% @",weakSelf.name);
    };
    self.block();
Copy the code

What if I add another delay operation?

    __weak typeof(self) weakSelf = self;
    self.block = ^(void){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@ "% @",weakSelf.name);
        });
    };
    self.block();
Copy the code

At this timeweakSelf.nameAlready empty. It was released before it had time to react. So how do we solve this?

    __weak typeof(self) weakSelf = self;
    self.block = ^(void){
        __strong __typeof(weakSelf) strongSelf = weakSelf;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@ "% @",strongSelf.name);
        });
    };
    self.block();
Copy the code

weak``strongReasonable application arrangement. The inside of the blockstrongSelfIs a temporary variable that is released when out of scope.

Self -> block -> self -> block

    __block ViewController *vc = self;
    self.block = ^(void){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@ "% @",vc.name);
            vc = nil;
        });
    };
    self.block();
Copy the code

Solution three: Introduce arguments, then self is not captured

   self.block = ^(ViewController * vc){
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@ "% @",vc.name);
        });
    };
    self.block(self);
Copy the code

Weak

Does the following code block cause a circular reference?

static ViewController *staticSelf_;
- (void)blockWeak_static {
    // It is the same memory space
    __weak typeof(self) weakSelf = self;
    staticSelf_ = weakSelf;
}
Copy the code

Run to find that dealloc does not walk, so a circular reference is created. Analysis:weakSelfandselfIt’s pointing to the same memory space.At this timestaticSelf_ = weakSelfAfter the global variable is heldself, so it will not be released.

Next, does the following create a circular reference?

- (void)block_weak_strong {
    __weak typeof(self) weakSelf = self;
    self.doWork = ^{
        __strong typeof(self) strongSelf = weakSelf;
        weakSelf.doStudent = ^{
            NSLog(@ "% @", strongSelf);
        };
       weakSelf.doStudent();
    };
   self.doWork();
}
Copy the code

Run to find that dealloc does not walk, so it also creates a circular reference. Analysis:NSLog(@"%@", strongSelf);This row, block pairsstrongSelfTo capture, at this pointstrongSelf.count+1, so it will not be freed. Solution: Don’t introduce thisstrongSelf