preface

This article will cover block types, circular references, and related interview questions, and the next article will verify and analyze these upper-level representations using the underlying source code.

Type of block

  • 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 local 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

GlobalBlock example:

- (void)viewDidLoad { void (^block)(void) = ^{ }; NSLog(@"%@",block); } <__NSGlobalBlock__: 0x104171100>Copy the code

MallocBlock example:

- (void)viewDidLoad { int a = 18; Void (^) block (void) = ^ {/ / the default strong reference NSLog (@ "SSL - % d", a); }; NSLog(@"%@",block); } <__NSMallocBlock__: 0x6000012B5ce0 >Copy the code

StackBlock example:

- (void)viewDidLoad { int a = 18; Void (^ __weak block) (void) = ^ {/ / weak references NSLog (@ "SSL - % d", a); }; NSLog(@"%@",block); } <__NSStackBlock__: 0x7ffee5569408>Copy the code

2, Block interview question

1)

- (void)blockDemo {// NSObject *objc = [NSObject new]; NSLog(@"%ld",CFGetRetainCount((__bridge CFTypeRef)(objc))); // double void(^strongBlock)(void) = ^{NSLog(@"-- --%ld",CFGetRetainCount((__bridge CFTypeRef)(objc))); }; strongBlock(); Void (^__weak weakBlock)(void) = ^{NSLog(@"-- --%ld",CFGetRetainCount((__bridge CFTypeRef)(objc))); }; weakBlock(); // fourth time void(^mallocBlock)(void) = [weakBlock copy]; mallocBlock(); } Execution result: --1 --3 --4 --5Copy the code
  • First print, just initialize, reference count is1.
  • Second print, stackblockrightobjcDo a capture reference count+ 1, stack memory assignment to heap memory reference count again+ 1, so the reference count is3.
  • Print the third time, because it is weak reference stackblockrightobjcDo a capture reference count+ 1, so the reference count is4.
  • Fourth print, stackblockAssign values to the pileblockReference counting+ 1, so the reference count is5.

2)

- (void)blockDemo { int a = 18; void(^__weak block1)(void) = nil; { void(^__weak block2)(void) = ^{ NSLog(@"---%d", a); }; block1 = block2; NSLog(@"1 - %@ - %@",block1,block2); } block1(); } Result: 1 - <__NSStackBlock__: 0x7ffeeb3b33e0> - <__NSStackBlock__: 0x7ffeeb3b33e0> --18Copy the code
  • block2andblock1Is is the stackblock, the scope isblockDemo3It’s all valid inside the function, soblock1()It can be executed normally.

3) remove the __weak modifier from block2:

  • block2andblock1Is is the heapblock.block2It’s created in a code block, it’s only valid in a code block, it’s destroyed when it’s out of a code block,block1And point to theblock2, so callblock1()Will collapse.

Block loop reference

Loop through the sample code

typedef void(^SSLBlock)(void); - (void)viewDidLoad { [super viewDidLoad]; // loop through self.name = @" SSL "; self.block = ^(void) { NSLog(@"%@",self.name); }; [UIView animateWithDuration:1 animations:^{NSLog(@"%@",self.name);}]; }Copy the code
  • The first piece of code becauseblockandselfThey hold each other, so circular references are created.
  • Second codeselfThey don’t holdview, so there is no circular application.

__weak resolves circular references

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.name = @"ssl";
    __weak typeof(self) weakSelf = self;
    self.block = ^(void) {
        NSLog(@"%@",weakSelf.name);
    };
}
Copy the code
  • weakSelfA weak referenceselfThe reference count will not increment1So even thoughweakSelfbeblockHolding, it’s not going to increaseselfThe reference count does not generate circular references.

If there is an asynchronous operation in the block and we want the operation to continue after the page returns, we need to add strongSelf:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.name = @"ssl";
    __weak typeof(self) weakSelf = self;
    self.block = ^(void){
        __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
  • There’s a question mark herestrongSelfIt’s a strong reference, does it cause a circular reference again? No because it’s a temporary variable, it’s released at the end of its scope.

Manually set nil to solve circular references

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.name = @"ssl";
    __block ViewController *vc = self;
    self.block = ^(void) {
        NSLog(@"%@",vc.name);
        vc = nil;
    };
    self.block();
}
Copy the code
  • This approach can also work with circular references, but there is a drawbackblockMust be called, onlyblockIs called thevcCan be set to zeronilOtherwise, circular references will still be generated.
  • It has to be used here__blockOtherwise an error will be reported, which will be parsed in the next article.

Pass parameters to resolve circular references

typedef void(^SSLBlock)(ViewController *vc);

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.name = @"ssl";
    self.block = ^(ViewController *vc) {
        NSLog(@"%@",vc.name);
    }; 
    self.block(self);
}
Copy the code
  • blockExternal variables are captured, in this case by passing in parameters, which do not need to be captured, so circular references can be resolved.

4, Block cycle reference interview questions

1)

static ViewController *staticSelf_;

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self blockWeak_static];
}
- (void)blockWeak_static {
    __weak typeof(self) weakSelf = self;
    staticSelf_ = weakSelf;
}
@end
Copy the code
  • This code is also memory leaking,weakSelfIt’s a weak reference, but it also points toselfThe memory space of the reference count is not added1Just passstaticSelf_ = weakSelfThis code right here,staticSelf_It also points toselfMemory space,staticSelf_Global static variables are not released,selfIt’s not going to be released so you have a memory leak.

2)

typedef void(^SSLBlock)(void);

@interface ViewController ()
@property (nonatomic, copy) SSLBlock doWork;
@property (nonatomic, copy) SSLBlock doStudent;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self block_weak_strong];
}
- (void)block_weak_strong {
    __weak typeof(self) weakSelf = self;
    self.doWork = ^{
        __strong typeof(self) strongSelf = weakSelf;
        weakSelf.doStudent = ^{
            NSLog(@"%@", strongSelf);
        };
       weakSelf.doStudent();
    };
   self.doWork();
}
@end
Copy the code
  • This code is going to loop through,doWorkWithin thestrongSelfTemporary variables in the current scope do not generate circular references,doStudenttostrongSelfTherefore, a circular reference is generated. Be careful to deleteweakSelf.doStudent()Again, circular references.