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 externalobjc
What is the reference count?Analysis: The problem here is mainly instrongBlock()
Here, we follow our common sensestrongBlock
Capture objc so +1 should be 2, so why print 3? The reason herestrongBlock
Is a heap block, it is copied from the stack to the heap, so here also +1, specific we below combined with the source codelibclosure
Analysis. 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 blockstrongBlock
The 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 timestrongBlock
It’s a heap areablock
Pile, theblock
Assigned toweakBlock
Turn the Block into a heap areablock
butstrongBlock
It’s released after it’s out of scope, so theta at this pointweakBlock
The 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
- manual
copy
block
As a return value- Being strongly quoted or
copy
modified - The system API contains
usingBlock
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.name
Already 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``strong
Reasonable application arrangement. The inside of the blockstrongSelf
Is 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:weakSelf
andself
It’s pointing to the same memory space.At this timestaticSelf_ = weakSelf
After 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 pairsstrongSelf
To capture, at this pointstrongSelf
.count+1, so it will not be freed. Solution: Don’t introduce thisstrongSelf