• Block详解二(底层分析)


    Block专辑:

    Block讲解一

    MRC-block与ARC-block

    Block详解一(底层分析)

    今天讲述Block的最后一篇,后两篇仅仅是加深1,2篇的理解,废话少说,开始讲解!

    • __block细节
    • __block内存管理
    • 循环引用问题

    一:__block细节

    大家可能会遇到下面的问题,block的内部想要修改外部的auto变量,但是编译器会报问题!如下

    如果block内部想要修改外部的auto变量,可以在int age 前面加入static修饰词,变为静态局部变量(会一直存在内存中,反而不好),以及可以将int age代码移植到函数外面变为全局变量! 除此之外还有没有其他的做法了呢,显然是有的,通过__block修饰,如下:

    发现__block修改外面变量是可以达到目的的! 小结论

    1. __block可以用于解决block内部无法修饰auto变量值的问题
    2. __block不能修饰全局变量、静态变量(static)
    3. 编译器会将__block变量包装成一个对象

    通过命令

    xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m

    生成main.cpp代码查看原理

    上面提到可以将int main函数的代码简化一下,简化成如下

    首先拿到forwarding指针然后再拿到age的值

    二:__block的内存管理

    1. 当block在栈上时,并不会对__block变量产生强引用;

    2. 当block被copy到堆时

    1. 会调用block内部的copy函数
    2. copy函数内部调用_Block_object_assign函数
    3. _Block_object_assign函数会对__block变量形成强引用(retain)

     3.当block从堆中移除时

    1. 会调用block内部的dispose函数
    2. dispose函数内部会调用_Block_object_dispose函数
    3. _Block_object_dispose函数会自动释放引用的__block变量(release)

    拓展:__block的_forwarding指针

     栈上block的forwarding指针指向堆上的block,而堆上block的forwarding指针指向自己本身的指针。

     三:循环引用

     关于block循环引用的基本概念,专辑block已经讲解,本篇讲述核心内容

    1. 解决循环引用问题-ARC

    (1) 用__weak、__unsafe_unretained解决

     下面用例子来巩固下

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            Person *person = [[Person alloc]init];
            __weak Person *weakPerson = person;
            person.block = ^{
                NSLog(@"age is %d", weakPerson.age);
            };
        }
        NSLog(@"1111111");
        return 0;
    }
    
    #import <Foundation/Foundation.h>
    NS_ASSUME_NONNULL_BEGIN
    typedef
    void(^ZXYBlock)(void);
    @interface Person : NSObject
    @property(nonatomic,copy)ZXYBlock block; @property(assign, nonatomic)
    int age; @end #import "Person.h" @implementation Person -(void)dealloc { NSLog(@"%s", __func__); } @end

    __weak方式解决循环引用问题

    __unsafe_unretained方式解决循环引用问题

     __weak,__unsafe_unretained都可以解决循环引用,有什么区别呢?

    结论

    相同点:__weak和__unsafe_unretained都不会产生强引用

    不同点:__weak指向对象销毁时,会自动让指针置为nil;__unsafe_unretained不安全,指向对象销毁时,指针存储地址         不变,如果再次访问可能会造成野指针

     (2) 用__block方式解决

    下面来探究一下为什么__block可以解决循环引用?看下编译成的c++代码

    以前结合__block 对象变量以及__block自动变量可知:c++包含了三个对象,如下

     上面的三种关系如下,调用person = nil就是为了打断其中一个循环引用链条,但是必须要调用block()

    2. 解决循环引用问题-MRC

    MRC下,首先要在编译器上设置为MRC环境。Build Settings->Automatic Reference Counting设为No

    (1) 用__unsafe_unretained解决

    因为MRC下不存在弱指针,所以不存在__weak修饰解决循环引用

    (2) 用__block解决

    总结

    上面是block最后一篇的讲解,关于block总共有四篇博客,应该可以讲解完所有关于block的内容,应该会大大增加大家对block底层的理解,如果觉得有意义有所帮助,欢迎点赞和关注,本人会及时更新博客!!!

  • 相关阅读:
    【40讲系列1】数组、链表
    更改凭证类型
    将公司代码设置给生产性的(不能删除业务数据的配置)
    使用参考过账
    查看凭证行项目
    查看凭证过账行项目
    预制凭证
    做凭证时凭证日期等于过账日期
    英语-20210302
    自动计算税额
  • 原文地址:https://www.cnblogs.com/guohai-stronger/p/12518714.html
Copyright © 2020-2023  润新知