Small valley bottom exploration collection

  • blockThis thing – basic is closely related with our life, 😆, after all, with too much. Today, brothers, let’s exploreblockWhat is it? 🐯

1. blockclassification

  • Real men don’t beat around the bush. – code

1.1. The globalblock

    void (^block)(void) = ^ {NSLog(@"xiaogu");
    };
    NSLog(@ "% @",block);
Copy the code
  • Output:

Global block when there are no external variables

1.2. The heap areablock

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

There are external variables that are introduced that become heap blocks

1.3. The stack block

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

With __weak, it becomes a stack block

2. blockA circular reference

I bet my bottom line: all my brothers who use blocks have experienced circular references

    1. A circular reference(I like to speak in plain English) is: I hold you, you hold me. The result can not put open ~
    1. Here’s an example:
typedef void(^XGBlock)(void);
@interface XGTestVC(a)
@property(nonatomic.copy)XGBlock block;
@property(nonatomic.copy)NSString * name;
@end

/ / implementation
    self.name = @"xiaogu";
    self.block = ^(void) {NSLog(@ % @ - "".self.name);
    };
    self.block();

Copy the code

This creates a circular reference to self — hold –> block — hold –> self

    1. If you’re testing, you can write adeallocMethod to see if the exit interface is released
- (void)dealloc
{
    NSLog(@"dealloc");
}
Copy the code

2.1. Solutions

  • When we have a problem, there are all kinds of solutions. Today, I’ll talk to you guys about a few

2.1.1. The Dance of strength and weakness (strong - weak - dance)

I’m sure everyone’s heard that word. Today I will present a wave of ugly ~

    1. Just begin to doiOSThe solution my brothers came up with was to solve the dependency and then do a waveweakSelf
    __weak typeof(self) weakSelf = self;
    self.block = ^(void) {NSLog(@ % @ - "",weakSelf.name);
    };
Copy the code

Then you find that the circular reference is really solved, and leave it alone

becauseweakSelfThis adds to the weak reference list, and you don’t know when to release. ifblockThere are time-consuming operations in, so this might benil the

    1. Dance between strong and weak (strong - weak - dance), come ~ show ~
    __weak typeof(self) weakSelf = self;
    self.block = ^(void){
        __strong __typeof(weakSelf)strongSelf = weakSelf;
        // It takes time to operate something
        NSLog(@ % @ - "",strongSelf.name);
    };
Copy the code

This is the dance of strength and weakness, strongSelf’s life cycle will be released in block code blocks, which is a perfect solution (I feel) ~ because I like it, 😆

2.1.2. Intermediate mode — Manual release

Of course, there are also brothers who do not like to dance strong and weak, that can also be manually released

  • __blockExternal variables can be modified. So let me do this
    __block XGTestVC *tvc = self;

    self.block = ^(void) {// It takes time to operate something

        NSLog(@ % @ - "",tvc.name);

        // set nil when used up
        tvc = nil;
    };
Copy the code

This also resolves circular references. After all, TVC is scoped, out of scope is released

2.1.3. Value transmission mode

    1. There’s nothing left to say here, just pass a value, he doesn’t hold it, it doesn’t cause a circular reference
    1. If if the circular reference, I prefer the strong and weak dance to solve the convenient, which makes people very comfortable after all, 😆

3. blockStructure to explore

The above solutions are very simple to say, the next is the highlight ~

3.1. The globalblock

    1. Let’s do an easy one firstblock

    1. Those of you who read my original blog already know what I’m going to read.

xcrun -sdk iphonesimulator clang -rewrite-objc main.m

    1. I can figure it out.cppCompared the under

A block is just a structure, so it can print at sign, % at sign, and then it has its own constructor.

~ xgblock->FuncPtr(xgblock); ~(xgblock) The session is passed in the form of hidden parameters

3.2. The heapblock

    1. So let’s see, what happens if we introduce an external parameter
        int a = 180;
        void (^xgblock)(void) = ^ {NSLog(@"xiaogu-height-%d",a);
        };
        xgblock();
Copy the code

😆, let’s xcrun-Clang take a look

Stack of words on their own, ha ha ha 🙄

3.2.1. __blockmodified

The __block modifier is used to change the external value of a block block, so what does __block do

    1. The test code
       __block int a = 180;
        void (^xgblock)(void) = ^{
            a++;
            NSLog(@"xiaogu-height-%d",a);
        };
        xgblock();
Copy the code
    1. wexcrun-clangLook at the

    1. We see through__blockAfter modification, there’s this one. Let me show you the whole thing

    1. Conclusion: Approved__blockAfter modifying the variable, a structure is generated. The structure then stores the variables and changes the values in the structure as it changes them. (In fact, the original variable into the corresponding object)

4. blockSource code analysis

4.1. Locate the source code

Before we start, we need to solve a problem: we don’t know where the source code for Block is. See who

    1. First we need to locate the source code. (The following is my positioning process ~)

    1. After we find the source code. It’s comfortable. This source code can be compiled. So debugging is very comfortable ~) (I use the latest source code with the brothers to go round)

4.2. blockStack – > pile

    1. I read a lot onlineblockBlog, will say:blockFrom the stack area, and thencopyPile areablock
    1. Guys, we need to get to the bottom. We need to feel it_Block_copyWhat have you done? How do I get from stack to heap
    1. So let’s write a heap areablock
        __block int a = 10;
        void (^mallocBlock)(void) = ^void {
            a++;
        };
        NSLog(@"MallocBlock is %@", mallocBlock);
Copy the code
    1. Then by locating the source code during the process, we know it will execute_Block_copy(this is actually the key method), and we can debug 😆, so let’s break to 😆

    1. And then let’s look at his value when he comes in

Now it’s still a stack block.

    1. Hey hey. 😝, let’s see how he becomes a heapblock. I first put the code affixed, can also help the brothers without source ~
void *_Block_copy(const void *arg) {
    struct Block_layout *aBlock;

    if(! arg)return NULL;
    
    // The following would be better done as a switch statement
    aBlock = (struct Block_layout *)arg;
    if (aBlock->flags & BLOCK_NEEDS_FREE) {
        // latches on high
        latching_incr_int(&aBlock->flags);
        return aBlock;
    }
    else if (aBlock->flags & BLOCK_IS_GLOBAL) {
        return aBlock;
    }
    else {
        // Its a stack block. Make a copy. - If it is a stack block, copy it
        struct Block_layout *result =
            (struct Block_layout *)malloc(aBlock->descriptor->size);
        if(! result)return NULL;
        memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
#if __has_feature(ptrauth_calls)
        // Resign the invoke pointer as it uses address authentication.
        result->invoke = aBlock->invoke;
#endif
        // reset refcount
        result->flags &= ~(BLOCK_REFCOUNT_MASK|BLOCK_DEALLOCATING);    // XXX not needed
        result->flags |= BLOCK_NEEDS_FREE | 2;  // logical refcount 1
        _Block_call_copy_helper(result, aBlock);
        // Set isa last so memory analysis tools see a fully-initialized object.
        result->isa = _NSConcreteMallocBlock;
        returnresult; }}Copy the code
    1. My breakpoint debugging

Malloc allocates memory space for receiving blocks

Copy the block to the newly allocated memory by memmove

Set the block object type to heap block, result-> ISA = _NSConcreteMallocBlock

4.3. blockThree layerscopy

It is said that this is, the interview does not zha ask, but with brothers drink boast force easy to say the technical point 😆

    1. When using__blockThe modified variable is an object
        __block NSString *name = [NSString stringWithFormat: @"XG"];
        
        void(^blockCopy)(void) = ^{
            name = @"xiaogu";
            NSLog(@ "% @",name);
        };
        blockCopy();
Copy the code
    1. And then we usexcrunget.cppfile
// name the initial assignment __Block_byref_name_0 modifier. (Struct assignment, corresponding to __Block_byref_name_0)
 __attribute__((__blocks__(byref))) __Block_byref_name_0 name = {
 (void*)0,
 (__Block_byref_name_0 *)&name,
 33554432.sizeof(__Block_byref_name_0), __Block_byref_id_object_copy_131, __Block_byref_id_object_dispose_131, ((NSString * _Nonnull (*)(id, SEL, NSString * _Nonnull, ...) ) (void *)objc_msgSend)((id)objc_getClass("NSString"), sel_registerName("stringWithFormat:"), (NSString *)&__NSConstantStringImpl__var_folders_6j_hfrbcdq96lsbr8vr1qjw1fkm0000gn_T_main_b45ce1_mi_0)
 
 };


// the __Block_byref_name_0 structure
 struct __Block_byref_name_0 {
   void *__isa;
 __Block_byref_name_0 *__forwarding;
  int __flags;
  int __size;
  void (*__Block_byref_id_object_copy)(void*, void*);
  void (*__Block_byref_id_object_dispose)(void*);
  NSString *name;
 };

static void __Block_byref_id_object_copy_131(void *dst, void *src) {
 _Block_object_assign((char*)dst + 40, * (void((* *)char*)src + 40), 131);
}
static void __Block_byref_id_object_dispose_131(void *src) {
 _Block_object_dispose(*(void((* *)char*)src + 40), 131);
}


/ / block, block
// This will not be mentioned ~ after all, brothers already have the conditions to explore, ~ as mentioned above, memory copy will occur.
void(*blockCopy)(void) = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_name_0 *)&name, 570425344));
        ((void (*)(__block_impl *))((__block_impl *)blockCopy)->FuncPtr)((__block_impl *)blockCopy);
Copy the code

I’m debugging with a source, so it’s easier to understand

    1. To summarize it briefly: Pass__blockModifier, and the variable is an objectcopy
    • 3.1. The first layer of copy is _Block_copy –> its own copy –> slave stack –> heap

    • Copy: _Block_byref_copy–> Copy the modified object to the Block_byref structure type

    • 3.3. Layer 3 copy:_Block_object_assign, which modifies __Block_byref_id_object_copy_131 for the current __block object

OK,, ah, the end of the year, very busy, I have to work overtime. O (╥ man ╥) o