This is the 28th day of my participation in the August Challenge

How many blocks do you know? How many solutions do you have for cyclic references to blocks?

IOS Basic Block Exploration (1) — Getting to know Blocks (How many blocks do you know?)

I’ve covered block types in my last blog post, so this blog will skip right to the topic and show you how to solve the problem of circular block references.

1. Why circular reference analysis

1.1 Normal Conditions

Under normal circumstances,AHold the B.BtheReference count +1whenA On releaseB Send a signal,BAccept toreleaseAfter the signal,Reference count -1.

Normal use, normal release is not a circular reference problem, but if you have me, I have you in the situation, there will be a circular reference problem. A more vivid metaphor is the story of crane clams competing.

1.2 Reasons for circular Reference

Mutual holding cannot be released, as shown below:

The problem with circular references is that both A and B hold each other, and neither of them can be released. A can’t call dealloc and send A release message to B, and B can’t call dealloc until it receives A release message and the reference count is not reduced, so it can’t call dealloc to release.

So what about circular references?

1.3 Solution of Circular Reference

The solution to circular references is to break out of mutual holding, either way.

2. Solutions

Let’s start with an example of a circular reference, as follows:

The reason for the circular reference here is:

Self holds the block, and inside the block holds self, forming a closed loop, holding each other, unable to release.

So let’s look at the following: 👇 does this code have a circular reference?

[UIView animateWithDuration:0.25 animations:^{
		self.name = @"reno";
	} completion:nil];
Copy the code

The 👆 code above does not have a circular reference problem. Currently UIView holds a block, self does not hold a block, so there is no circular reference problem here.

So, how to solve the problem of circular reference? Please keep reading! 👇

2.1 __weak Resolves circular references

The first method is to use __weak, which is probably familiar, as follows:

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

This is not a problem, but if the block uses a delay function, the VC will still be destroyed, as follows:

2.2 Strong-weak-dance Loop Reference

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

Many ask: What went wrong here? Here is a delay function which is asynchronous. When VC is destroyed, the block is also released, and the printed name in the delay function cannot be printed, so the following situation occurs:

Judging from the print,deallocMethod is called,VCIt’s been destroyed,blockAnd it releases, the internal delay function doesn’t have time to print, sonamefornull. So how to solve it? The solution is as follows:

Since __weak is automatically set to nil, __strong(strong-weak-dance) is used to temporarily extend the life of self so that it can be printed properly.

So why isn’t there a circular reference problem here? Because strongSelf is a temporary variable, it’s released when it’s out of scope, so there’s no circular reference, this is the strong and weak dance.

2.3 Manual mode to solve circular reference

Some people like manual cars, like that kind of control feeling, especially exciting, so next I will introduce a manual way to solve the problem of circular reference.


__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

Here, after using a temporary VC variable, the holding relationship is: Self – > block > VC — – > self, after completion of the block, the use of VC is set to nil, block forming of the self hold relationship, so this does not constitute a circular reference, this is good, the wave action is to slip! 😁

The use of __block here is due to the need for external variables, assignment operations, pay attention to me, the next chapter will be on the block source code analysis, stay tuned!

2.4 Parameter Form Solves circular reference

Above 👆 manual operation method you get? Here’s an even better way to do it:


typedef void(^JP_Block)(ViewController*);

@property (nonatomic.strong) JP_Block JPBlock;

- (void)parameterMethod{

	self.JPBlock = ^(ViewController *vc){

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

The way arguments are used here, there is no problem with circular references. Wow! How easy!

So this is how to solve the block circular reference problem, have you learned? If you have a better way, welcome to the comment area message exchange!

More content continues to be updated

🌹 if you like, give it a thumbs up 👍🌹

🌹 feel harvest, can come to a wave, collection + attention, comment + forward, so as not to find me next time 😁🌹

🌹 welcome everyone to leave a message exchange, criticism and correction, learn from each other 😁, improve themselves 🌹