Block深入浅出

    • 研究工具

      • clang 为了研究编译器的实现原理,我们需要使用 clang 命令。clang 命令可以将 Objetive-C 的源码改写成 C / C++ 语言的,借此可以研究 block 中各个特性的源码实现方式。
      • clang -rewrite-objc main.m
      • main.m中不能包含UIKit框架,命令行中解析无法识别。包含#import <Foundation/Foundation.h>是可以支持的
    • C语言中变量有哪几种
      • 自动变量
      • 函数参数
      • 静态变量
      • 静态全局变量
      • 全局变量
    • 每种变量类型在Block中的特性及原理
      • 自动变量

        • 不可以修改,携带__block修饰可以被修改
        • 会被Block持有(retainCount+1)
        • 不带__block修饰的会被copy进Block
      • 函数参数 
        • 可以直接修改
        • 不会被Block持有(retainCount不会增加)
      • 静态变量
        • 可以被修改 - 由于传递给Block是内存地址值,查看Block的具体实现(查看clang后的main.cpp文件)
      • 静态全局变量和全局变量
        • 可以直接被访问和修改 - 由于存储区域在区全局区,由于作用区域的原因
        • 不会被Block持有(retainCount不会增加)
    • Block中改变变量值的方式
      • 传递内存地址到Block

        • 指针所指向的内存不可修改,但是内存中存放的数据可以修改
        • NSMutableString 变量可以直接在Block体中被appendString,但是不可以被=
      • 使用__block修饰
        • Block会将此标识符修饰的变量转化成一个结构体,Block体中传递并且使用的是这个结构体
        • __block int i 会被转换成
        • struct __Block_byref_i_0 {
            void *__isa; //指向自己
          __Block_byref_i_0 *__forwarding; //指向自己,当被copy到堆(heap)上时,原Block此字段指向堆上的Block地址,对上的此字段仍然指向自己。这样不管__block怎么复制到堆上,还是在栈上,都可以通过(i->__forwarding->i)来访问到变量值。
           int __flags;
           int __size;
           int i;

          };

      • Block捕获外部变量仅仅只捕获Block闭包里面会用到的值,其他用不到的值,它并不会去捕获。而且Block能捕获的变量只有自动变量和静态变量了。
    • Block的种类
      • _NSConcreteStackBlock

        • 只用到外部局部变量、成员属性变量,且没有强指针引用的block都是StackBlock
        • StackBlock的生命周期由系统控制的,一旦返回之后,就被系统销毁了
        • 不持有对象
      • _NSConcreteMallocBlock
        • 有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为MallocBlock
        • 没有强指针引用即销毁,生命周期由程序员控制
        • 持有对象
      • _NSConcreteGlobalBlock
        • 没有用到外界变量或只用到全局变量、静态变量的block为_NSConcreteGlobalBlock
        • 生命周期从创建到应用程序结束
        • 不持有对象
      • ARC下,系统会根据下面的规则决定是否将Block复制到heap上
    • 系统调用copy对Block复制的情况
      • 手动调用copy(当Block为函数参数的时候,就需要我们手动的copy一份到堆上了。这里除去系统的API我们不需要管,比如GCD等方法中本身带usingBlock的方法)
      • Block是函数的返回值
      • Block被强引用(Block被赋值给__strong或者id类型)
      • 调用系统API入参中含有usingBlcok的方法
    • __block堆栈拷贝
      • MRC 只有发生了copy,__block修饰的对象才会被copy到堆上
      • ARC 发生了copy或者=(block 类型通过=进行传递时,会导致调用objc_retainBlock->_Block_copy->_Block_copy_internal方法链),__block修饰的对象才会被copy到堆上
      • __block修饰的对象才会被copy到堆上 : __NSStackBlock__ 类型的 block 转换为 __NSMallocBlock__ 类型
    • clang代码转换
      • main.m 文件30行,大小831字节。转换后main.cpp 文件104810行,大小3.1MB。
    • Block 循环引用
      • 引起循环引用的条件其实很苛刻:

        • Block需要被相关类(当前类或者嵌套引用的某各类)strong或copy等类似操作
        • Block体中使用self(包括成员变量,成员属性等)
      • 发生循环引用的拆解方式:
        • 使用__weak对self进行弱引用,其实是通过弱引用的方式将闭环解开

          • __weak __typeof(self) wself = self;
            self.myBlock = ^{
                __strong __typeof(wself) self = wself;
                // 使用self进行相关操作即可
            };
        • 使用形参的方式,将self作为参数传递给Block
      • 常见易混淆的场景(前提:Block没有被strong或copy的情况下,即苛刻条件中的第一条)
        • GCD,系统动画等系统Block API,Block体中直接使用self不会有问题
        • Block体中使用了成员属性或者成员变量,不会有问题 (参考Block种类)
        • 访问了静态变量,全局变量,全局静态变量,不会引起问题
时间: 2024-10-13 16:38:02

Block深入浅出的相关文章

让我们来深入浅出block吧

http://www.jianshu.com/p/e03292674e60 开始之前,我想先提几个问题,看看大家是否对此有疑惑.唐巧已经写过一篇对block很有研究的文章,大家可以去看看(本文会部分引用巧哥文中出现的图和代码).在巧哥的基础上,我补充一些block相关的知识点和代码,并且概括并修正一些观点. 1.block是什么?block是对象吗? 2.block分为哪几种?__blcok关键字的作用? 3.block在ARC和MRC下的区别? 4.block的生命周期? 5.block对于以

HTTP深入浅出 http请求

HTTP深入浅出 http请求 HTTP(HyperText Transfer Protocol)是一套计算机通过网络进行通信的规则.计算机专家设计出HTTP,使HTTP客户(如Web浏览器)能够从HTTP服务器(Web服务器)请求信息和服务,HTTP目前协议的版本是1.1.HTTP是一种无状态的协议,无状态是指Web浏览器和Web服务器之间不需要建立持久的连接,这意味着当一个客户端向服务器端发出请求,然后Web服务器返回响应(response),连接就被关闭了,在服务器端不保留连接的有关信息.

Hadoop深入浅出-001

Doc By xvGe  Hadoop深入浅出-001 什么是Hadoop? The Apache Hadoop project develops open-source software for reliable,scalable,distributed,computing. Hadoop解决的问题: --海量数据存储 --海量数据分析 --资源管理调度 作者:Doug Cutting ********************************* (1)hadoop核心组件及文件系统概念

Android Handler消息机制深入浅出

作为Android开发人员,Handler这个类应该是再熟悉不过了,因为几乎任何App的开发,都会使用到Handler这个类,有些同学可能就要说了,我完全可以使用AsyncTask代替它,这个确实是可以的,但是其实AsyncTask也是通过Handler实现的,具体的大家可以去看看源码就行了,Handler的主要功能就是实现子线程和主线程的通信,例如在子线程中执行一些耗时操作,操作完成之后通知主线程跟新UI(因为Android是不允许在子线程中跟新UI的). 下面就使用一个简单的例子开始这篇文章

(CZ深入浅出Java基础)设计模式笔记

一.面向对象思想设计原则 1.单一职责原则 其实就是开发人员经常说的"高内聚,低耦合",也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个.在设计模式中,所有的设计模式都遵循这一原则. 2.开闭原则 核心思想是:一个对象对扩展开放,对修改关闭.其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码.也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢?这就需要借助于抽象和

(CZ深入浅出Java基础)线程笔记

一.线程的引入 1.多线程概述 1.1.进程 a.正在运行的程序,是系统进行资源分类和调用的独立单位. b.每个进程都有它自己的内存空间和系统资源. 1.2.线程 a.是进程中的单个顺序控制流,是一条执行路径. b.一个进程如果只有一条路径,则称为单线程程序. c.一个进程如果有多条执行路径,则称为多线程程序. 1.3.小结 线程多的进程抢到CPU执行权的概率大,但是仍具有随机性. 2.Java程序运行原理 2.1.Java运行 Java命令会启动Java虚拟机,启动JVM,等于启动了一个应用程

深入浅出JMS之Spring和ActiveMQ整合的完整实例

第一篇博文深入浅出JMS(一)–JMS基本概念,我们介绍了JMS的两种消息模型:点对点和发布订阅模型,以及消息被消费的两个方式:同步和异步,JMS编程模型的对象,最后说了JMS的优点. 第二篇博文深入浅出JMS(二)–ActiveMQ简单介绍以及安装,我们介绍了消息中间件ActiveMQ,安装,启动,以及优缺点. 第三篇博文深入浅出JMS(三)–ActiveMQ简单的HelloWorld实例,我们实现了一种点对点的同步消息模型,并没有给大家呈现发布订阅模型. 前言 这篇博文,我们基于spring

iOS block 陷阱解析

一,前言 <深入浅出Cocoa多线程编程之block与dispatch quene> 本文源码下载:点此下载 二,block 注意事项 1,block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝. 如下代码: - (void)testAccessVariable { NSInteger outsideVariable = 10; //__block NSInteger outsideVariable = 10; NSMutableA

[Algorithm &amp; Machine Learning]CAML机器学习系列1:深入浅出ML之Regression家族

声明:本博客整理自博友@zhouyong计算广告与机器学习-技术共享平台,尊重原创,欢迎感兴趣的博友查看原文. 符号定义 这里定义<深入浅出ML>系列中涉及到的公式符号,如无特殊说明,符号含义均按下述定义解释: 符号 含义 \(x_j\) 第\(j\)维特征 \(x\) 一条样本中的特征向量,\(x=(1, x_1, x_2, \cdots, x_n)\) \(x^{(i)}\) 第\(i\)条样本 \(x_{j}^{(i)}\) 第\(i\)条样本的第\(j\)维特征 \(y^{(i)}\)