• iOS Block笔记总结


    前言:

    对block的简单笔记总结,
     

    1.本质:

    封装了函数调用和函数调用环境的对象
     
    2.block结构:
     
     
    3.block捕获变量:
    由于需要跨函数访问变量,所以需要捕获变量,(防止访问时已被销毁)
     - auto变量(基本数据类型):值捕获,超出作用域就被销毁了
     - static变量:指针捕获,
     - 全局变量:直接访问
     - self,也属于局部变量,(每个方法默认参数(self,_cmd))
     
    4.block类型:
     
    block类型
    环境
    copy
    存储区域
    NSGlobalBlock
    没有访问auto变量
    什么也不做
    程序的数据区域 .data
    NSStackBlock
    访问auto变量
    从栈赋值到堆上
    NSMallocBlock
    NSStackBlock 调用copy
    引用计数+1
     
    5.block 的copy:
    在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况:
    - Block 作为函数的返回值
    - 将block赋值给__strong指针时
    - block 作为Cocoa API中方法名含有usingBlock的方法参数
    - block作为GCD API的方法参数
     
    6.block内部访问对象类型的auto变量:
    当block内部访问了对象类型的auto变量时,
    - 如果block是在栈上,将不会对auto变量进行强引用
    - 如果block 被拷贝到堆上
    - 会调用block内部的copy函数,
    - copy函数内部调用 _Block_objct_assgin函数,
    - _Block_objct_assgin函数会根据auto变量的修饰符(__strong,__weak,__unsafe_unretained)做出对应的操作,类似retain(强引用、弱应用)
    如果block从堆上移除
    - 会调用block中的dispose函数
    - dispose函数内部调用_Block_objct_dispose函数
    - _Block_object_dispose函数会自动释放引用的auto变量,类似于release
     
    7.__block 修饰符
    编译器会将__block修饰的变量包装成一个对象
      - __block 可以用于解决block内部无法修改auto变量值的问题
      - __block不能修饰 static、全局变量
    - 当block在栈上是,并不会对__block对象强引用
    - 如果block 被拷贝到堆上,对__block对象是强引用
    - 当block被copy到堆上时,会调用block(desc)中的copy函数
    - copy函数内部调用 _Block_objct_assgin函数,
    - _Block_objct_assgin函数会对__block变量进行强引用(retain)
    - 如果是对象类型时,在__block变量中也会存在 内存管理函数(copy,dispose)
    - 当__block变量在栈中,不会对指向的对象产生强引用
    - 当__block变量被copy到堆时,会调用__block中的copy函数,
    - copy函数内部调用__Block_objct_assgin函数,该函数会根据对象的修饰符(__strong,__weak,__unsafe_unretained)做出对应的操作,类似retain(强引用、弱应用)(注意:仅限于ARC时会retain,MRC下不会retain)。

    如果block变量从堆上移除
    - 会调用block中的dispose函数
    - dispose函数内部调用_Block_objct_dispose函数
    - _Block_object_dispose函数会自动释放引用的__block变量,类似于release
    如果是对象类型时,也会调用
    - 会调用__block中的dispose函数
    - dispose函数内部调用_Block_objct_dispose函数
    - _Block_object_dispose函数会自动释放引用的auto变量,类似于release
     
    注意:当block内部对应__block对象都是强引用,
    struct __Block_byref_p_0 { // 包装成的结构体对象
      void *__isa;
    __Block_byref_p_0 *__forwarding;
     int __flags;
     int __size;
     void (*__Block_byref_id_object_copy)(void*, void*);
     void (*__Block_byref_id_object_dispose)(void*);
     Person *p;
    };
    
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      __Block_byref_p_0 *p; // by ref 指向包装成的g结构体对象指针
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, __Block_byref_p_0 *_p, int flags=0) : p(_p->__forwarding) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    
    
    static struct __main_block_desc_0 {
      size_t reserved;
      size_t Block_size;
      void (*copy)(struct __main_block_impl_0*, struct __main_block_impl_0*);
      void (*dispose)(struct __main_block_impl_0*);
    }
    
     
    结构:
     
     
     
     
    8.__block 结构体对象内部的__forwarding指针
     
     
     
    9.循环引用问题:
    ARC:
    __weak, 
    __unsafe_unreatined,不会产生强引用,不安全,缺点:对象销毁后,指针不会自动指向nil
    __block,缺点:必须手动调用执行block,并在block中把对象赋值nil,
    MRC:
    __unsafe_unretained
    __block block内不会进行retain操作
     
     
     

  • 相关阅读:
    ngx_os_init解析
    cacheline相关优化手段
    std::thread_local
    std::initializer_list<T>
    MySQL group by 注意事项
    MySQL IFNULL函数
    python nginx不同参数压测脚本
    完全卸载oracle11g步骤
    Maven常用命令(转载)
    项目SVN的IP地址发生变化时修改SVN为新的IP地址
  • 原文地址:https://www.cnblogs.com/liuwenqiang/p/13265584.html
Copyright © 2020-2023  润新知