• 研究工具

      • 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的生命周期由系统控制的,一旦返回之后,就被系统销毁了
        • 不持有对象
        • 对Block的retain,release造作无效,copy造作会变成_NSConcreteMallocBlock类型
      • _NSConcreteMallocBlock
        • 有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为MallocBlock
        • 没有强指针引用即销毁,生命周期由程序员控制
        • 持有对象
        • retain,release,copy操作生效,内存管理器中的计数会增加。(但retainCount始终为1)
      • _NSConcreteGlobalBlock
        • 没有用到外界变量或只用到全局变量、静态变量的block为_NSConcreteGlobalBlock
        • 生命周期从创建到应用程序结束
        • 不持有对象
        • retain,release,copy操作为空操作
      • 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需要被相关类(当前类或者嵌套引用的某各类)retain或copy等类似操作
        • Block体中使用self(包括成员变量,成员属性等)
      • 发生循环引用的拆解方式:
        • 使用__weak对self进行弱引用,其实是通过弱引用的方式将闭环解开

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

Block深入浅出的更多相关文章

  1. OC语言-block and delegate

    参考博客 OC语言BLOCK和协议 iOS Block iOS Block循环引用精讲 iOS之轻松上手block 深入浅出Block的方方面面 Block apple官方参考 1.定义一个block ...

  2. 深入浅出Cocoa多线程编程之 block 与 dispatch quene

    深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...

  3. [Cocoa]深入浅出Cocoa多线程编程之 block 与 dispatch quene

    深入浅出 Cocoa 多线程编程之 block 与 dispatch quene 罗朝辉(http://www.cppblog.com/kesalin CC 许可,转载请注明出处 block 是 Ap ...

  4. 深入浅出Block的方方面面

    内容大纲: 1.Blocks概要 2.Blocks模式 3.Block实质(面试常问重点) 1.Blocks概要 什么是Blocks:Blocks是C语言的扩充的功能,可以用一句话来表示Blocks的 ...

  5. 深入浅出-iOS Block原理和内存中位置

    Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 #简介 今天回顾一下blcok,基本 ...

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

    声明:本博客整理自博友@zhouyong计算广告与机器学习-技术共享平台,尊重原创,欢迎感兴趣的博友查看原文. 符号定义 这里定义<深入浅出ML>系列中涉及到的公式符号,如无特殊说明,符号 ...

  7. JavaScript深入浅出3-语句

    慕课网教程视频地址:Javascript深入浅出 程序由语句组成,语句遵守特定语法规则 块 block  {}   没有块级作用域 声明    var 异常   try catch finally 函 ...

  8. Block编程值得注意的那些事儿

    [深入浅出Cocoa]Block编程值得注意的那些事儿   [深入浅出Cocoa]Block编程值得注意的那些事儿 罗朝辉 (http://www.cnblogs.com/kesalin/) 本文遵循 ...

  9. 深入浅出谈存储:如何区别NAS、SAN与DAS

    深入浅出谈存储:如何区别NAS.SAN与DAS 2012年02月17日16:51 来源:新浪博客 作者:林沛满 编辑:曾智强 查看全文 赞(0)评论(1) 分享 标签: DAS , SAN , 存储系 ...

随机推荐

  1. C#关于外挂汉化的一些思考(API函数FindWindow,FindWindowEx,SendMessage)(转)

    这次我们试着运用C#的API函数去修改别的程序的标题文本(适用范围C#) 其实这是FindWindow,FindWindowEx,SendMessage的应用举例之一 也就是所谓的外挂汉化. 附:Wi ...

  2. contiki-main.c 一 打印观察 <contiki学习之五>

    说明: 本文依赖于 contiki/platform/native/contiki-main.c 文件. 在项目工程目录下的hello-world.c 文件里面,有许多的宏,但没有最关键的main() ...

  3. password安全之动态盐

    首先,我们看看什么是盐:http://zh.wikipedia.org/zh/%E7%9B%90_%28%E5%AF%86%E7%A0%81%E5%AD%A6%29 ,再MD5是d16e970d6e5 ...

  4. LVS 详解

    http://zh.linuxvirtualserver.org/node/25 http://chrinux.blog.51cto.com/6466723/1198748 http://www.cn ...

  5. 简化版可用于多线程的logger

    logger 嘛要高效,要简单.废话不多话. GitHub 地址 https://github.com/goldli/logger 本文所说的logger使用System.Logger做为NameSp ...

  6. c#线程问题(3)

    //执行回调函数 static void Main(string[] args) { UPPER = ; Thread thread1=new Thread(sops); thread1.Name = ...

  7. 《Entity Framework 6 Recipes》中文翻译——第十二章自定义EntityFramework对象(一)

    本章的方法探讨一些可以应用于对象和实体框架的流程定制.这些方法涵盖了许多“幕后”的东西,它可以使你的代码更统一,比如通过更关注应用程序核心业务规则执行的细节,应用范围更广泛.我们开始本章的一个方法,告 ...

  8. 故事板 — 视图切换(segue)与传值

    1.传值问题:为什么不能给控件的接口赋值 如执行Segue跳转 [self performSegueWithIdentifier:GAPlayeVideo sender:gaVideo]; //在跳转 ...

  9. sql 自定义函数--固定格式字符转时间类型

    遇到一个德国的客户,他们的时间格式是JJJJ-TT-DD HH:MM:SS,程序按照这个格式将时间插入数据库,但是在sql自带的转换函数convert.cast过程中报错,网上搜了下都说用conver ...

  10. VC2010 _com_error 返回的错误信息

    CString GetComError(const _com_error& e) { CString sMsg; sMsg.Format( _T("HRESULT: 0x%08lx; ...