The type of the block

We all use blocks in our daily development process, but what types of blocks do you know? Let’s look at the types of blocks.

There are three types of blocks

Three types of blocks are entered. Here are three types of blocks:

  • GlobalBlock

    • Located in global area
    • inblockDo not use external variables internally, or use only static and global variables
  • MallocBlock

    • Located in the heap area
    • inblockInternally use variables orocProperty and is assigned to a strong reference orcopyModified variable
  • StackBlock

    • Located in the stack area
    • withMallocBlockAgain, you can use local variables internally orocProperty, but cannot be assigned to a strong reference orcopyModified variable

Conditions under which blocks are copied to the heap

  • manualcopy
  • blockAs a return value
  • Being strongly quoted orcopymodified
  • systemapicontainsusingBlock

Related to the case

  • Case a

Here, we define a self-defined _CXBlock type structure. We make strong transformation of weakBlock and assign value to BLC, so that we can modify the data structure in the block. WeakBlock, strongBlock, strongBlock1 all point to the same block of memory, so when we set BLC invoke to nil, strongBlock1() execution will report an error and no function can be found. But when we change id __strong strongBlock = weakBlock to ID __strong strongBlock = [weakBlock copy], we can solve this problem. This is because the BLC is a heap block after the stack block is copied.

  • Case 2

Because a block captures external variables, it increments the reference count. The first printing of 3 is because the stack block and the heap block are referenced once, and the first printing of 4 is because this is a stack block, so the reference count is incremented. Printing 5 is because weakBlock changes to heap block after copying, and the reference count will be increased by 1.

  • Case 3

StrongBlock is a stack block, so strongBlock scope is the middle curly bracket end, so weakBlock = strongBlock can be assigned success, At this time, weakBlock is also a stack block, so its scope is at the end of the outermost braces, so weakBlock() can execute successfully. WeakBlock () does not execute if strongBlock is a heap block.

Block loop reference

The release condition of the object

Circular reference condition

Circular reference case

// loop through self.name = @"chenxi"; self.block = ^{ NSLog(@"%@",self.name); };Copy the code

In this case, circular reference will appear. We can use weakSelf to solve this problem, and the code is as follows:

  • Solve circular reference method one
    self.name = @"chenxi";
    __weak __typeof(self)weakSelf = self;
    self.block = ^{
        NSLog(@"%@",weakSelf.name);
    };
Copy the code

Although weakSelf’s method can indeed solve the problem of circular reference, this method is not perfect, which can be seen in the following cases:

Similarly, when we print, we add a delay, and in this case, when we go back too fast, the name is released before we can print, so we print null. To solve this problem we need to use strongSelf as follows:

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

Here strongSelf is only a temporary variable, extending the release time of weakSelf, but strongSelf scope is only in the block function, strongSelf will be released after the block function is executed.

  • Solve circular reference method 2
- (void)viewDidLoad {
    [super viewDidLoad];
    self.name = @"xhenxi";
    __block ViewController *vc = self;
    self.block = ^{
        NSLog(@"%@",vc.name);
        vc = nil;
    };
    self.block();
}
Copy the code

I’m using a temporary variable vc that accepts self and sets VC to nil when I’m done printing.

  • Solve circular reference method 3
typedef void(^CXBlock)(ViewController *vc);
@interface ViewController ()
@property (nonatomic, copy) CXBlock block;
@property (nonatomic, copy) NSString *name;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.name = @"xhenxi";
    self.block = ^(ViewController *vc) {
        NSLog(@"%@",vc.name);
    };
    self.block(self);
}
Copy the code

Here we’re passing self as an argument to the block.

Repeat relevant interview questions

  • Try a
static ViewController *staticSelf_; - (void)blockWeak_static { __weak typeof(self) weakSelf = self; staticSelf_ = weakSelf; } - (void)dealloc {NSLog(@"dealloc call "); }Copy the code

Similar to this code, we assign weakSelf to a global static variable staticSelf_, run command, dealloc method does not go, will not release. This is because weakSelf and self refer to the same memory space, so assigning weakSelf to staticSelf_ will result in memory not being freed.

  • Item 2
typedef void(^CXBlock)(void); @interface ViewController () @property (nonatomic, copy) CXBlock block; @property (nonatomic, copy) CXBlock doWork; @property (nonatomic, copy) CXBlock doStudent; @end - (void)block_weak_strong { __weak typeof(self) weakSelf = self; self.doWork = ^{ __strong typeof(self) strongSelf = weakSelf; weakSelf.doStudent = ^{ NSLog(@"%@", strongSelf); }; weakSelf.doStudent(); }; self.doWork(); } - (void)dealloc{NSLog(@"dealloc call "); }Copy the code

There is also a circular reference problem here, because doStudent will capture strongSelf, so the strongSelf reference count will be increased by one, so after doWork, strongSelf will not be released.