【Effective_Objective-C_6 块block】

news2024/11/15 17:36:52

文章目录

  • 前言
    • GCD和块的简介
    • 37.理解块的概念
        • 块的基础知识
            • 块可以捕获变量
          • 内联块的用法
        • 块的内部结构
        • 全局块,栈块,堆块
            • 堆块
            • 全局块
    • 要点
    • 38.为常用的块类型创建typedef
    • 要点
    • 39.用handler块降低代码分散程度
        • 协议传值实现异步
        • 块实现异步
        • 回调操作里的块
    • 要点
    • 40.用块引用其所属对象时不要出现保留环
        • 块中也存在保留环
    • 要点
  • 总结

前言

  • 本章的内容是比较麻烦复杂的一章,牵扯到了GCD和Block,在之前也有学习过,本章作以深入的了解
  • 多线程问题是开发应用程序的时候最让人头疼的问题,尤其是线程阻塞,在更新了Mac之后我经常的遇到了彩虹小球的问题,当然在开发的时候还没有出现过线程阻塞问题。

GCD和块的简介

  • Apple以块和大中枢派发设计了全新的多线程,也就是block和GCD。这是两种不同的技术,但都是一并引入的。
    • 块:这个机制方便我们把代码像对象一样传递,令其在不同的环境下运行,而且在定义块的范围内可以访问其中的全部变量
    • GCD:GCD是一种基于块的技术,它提供了对线程的抽象,而这种抽象则给予派发队列,开发者将块排入队列里面,适时地操纵处理队列,合理高效的完成开发
  • 块和GCD都是OC的重要内容,本章来学习原理和内容

37.理解块的概念

  • 块可以实现闭包,这个特性是作为扩展引入的,它也是基于C语言特性的技术,包括在C C++,OC,OC++代码使用它

块的基础知识

  • 块与函数类似,只不过是直接定义在另一个函数里的,和定义它的那个函数共享同一个范围内的东西。块用“^”符号来表示,后边跟着一对花括号,括号里面是块的实现代码
    • 简单的块
      请添加图片描述
^{
    block implementation 
}

  • 块也是一个值,它的语法和函数类似,语法结构如下
return_type (^block_name)(parameters)

    • 具体实例,这是☝️了一个名字为addBlock的块变量,可以类似于函数去使用它
NSString* (^addBlock)(NSString *a, NSString *b) = ^(NSString *a, NSString *b) {
    return [NSString stringWithFormat:@"%@%@", a, b];
};

请添加图片描述
请添加图片描述

块可以捕获变量
  • 块可以在它生命的范围里面所有变量都可以捕获。
    请添加图片描述
NSString *c = @"ff";
NSString* (^addBlock)(NSString *a, NSString *b) = ^(NSString *a, NSString *b) {
    return [NSString stringWithFormat:@"%@%@%@", a, b, c];
};
  • 当然在默认情况下我们捕获的C字符串是不可以修改的,不过声明变量的时候加入_block即可在块内修改
  • 第一次使用出现了错误 记录一下, 我把这个属性定义到了属性声明的位置,接下来放到内部实现局部变量即可
    请添加图片描述
__不允许块属性,仅允许在局部变量上 __block attribute not allowed, only allowed on local variables

请添加图片描述

内联块的用法
  • 如果块所捕获的变量是对象类型,那么就会自动保留它。系统在释放这个块的时候,也会将其一并释放。这就引出了一个于块有关的重要问题。块本身可视为对象。并且块本身也和其他对象一样,有引用计数
  • 如果将块定义在OC类的实例方法中,那么除了可以访问类的所有实例变量之外,还可以使用self变量。块总能修改实例变量,所以在声明时无需加_block。不过,如果通过读取或写入操作捕获了实例变量,那么也会自动把self变量一并捕获了,因为实例变量是与self所指代的实例关联在一起的。也就是说,只要你在块中调用到了属性值,那么这个块就会捕获这个类本身也就是self。
    请添加图片描述

块的内部结构

  • OC对象都会占用某个内存区域,块本身也是对象,也存在内存区域和内存布局请添加图片描述
  • 在存放块对象的内存区域中,首个变量是指向Class对象的指针,该指针叫做isa
  • 在内存布局中,最重要的就是invoke变量,这是个函数指针,指向块的实现代码。函数原型至少需要接受一个void*型的参数,此参数代表块,这其实就是一种代替函数指针的语法结构,把函数通过块封装成有用的接口
  • descriptor变量是指向结构体的指针,每个块里都包含此结构体,其中声明里块对象的总体大小,还声明里copy与dispose这两个辅助函数所对应的函数指针。
  • 块还会把它所捕获的所有变量都拷贝一份。这些拷贝放在descriptor变量的后面,捕获了多少个变量,就要占据多少内存空间。拷贝的并不是对象本身,而是指向这些对象的指针变量
  • invoke函数为何需要把块对象作为参数传进来呢?因为要从内存中把这些捕获到的变量读出来

全局块,栈块,堆块

  • 定义对象的时候是初始分配在栈上的,也就是有可能在使用之后内存被覆写,那样就是产生崩溃
    请添加图片描述
堆块
  • 为了解决问题可以给块对象发送copy信息,这样子就会把块从栈复制到堆上,块也就成了带引用计数的对象了,在ARC下编译器会自动的合理的释放对象。
    请添加图片描述
全局块

除了“栈块”和“堆块”之外,还有一类块叫做“全局块”。这种块不会捕捉任何状态(比如外围的变量),运行时也无须有状态来参与。而且全局块的copy属于空操作。可以把他认为是单例。

在使用单例模式封装网络请求的时候就是使用了全局块
请添加图片描述

要点

  • 块是C、C++、OC中的词法闭包。
  • 块可接受参数,也可返回值。
  • 块可以分配在栈上或堆上,也可以是全局的。分配在栈上的块可拷贝到堆里,这样的话,就和标准的OC对象一样,具备引用计数了。

38.为常用的块类型创建typedef

  • 上面那个单例模式封装网络请求的代码就用到了这一条。
  • 为了隐藏复杂的块类型,需要用到C语言的类型定义,typedef关键字。
typedef int (^EOCSomeBlock)(BOOL flag, int value);

请添加图片描述
如此以来与定义其他变量时一样,变量类型在左边,变量名在右边。

  • 块也可以用来简便方法签名
    请添加图片描述

要点

  • 以typedef重新定义块类型,可令块变量用起来更加简单。
  • 定义新类型时应遵从现有的命名习惯,勿使其名称与别的类型相冲突。
  • 不妨为同一个块签名定义多个类型别名。如果要重构的代码使用了块类型的某个别名,那么只需要修改相应typedef中的块签名即可,无须改动其他typedef。

39.用handler块降低代码分散程度

协议传值实现异步

  • 为用户界面编码时,一种常用的范式就是“异步执行任务”。这种范式的好处在于:处理用户界面的显示及触摸操作所用的线程,不会因为要执行I/O或网络通信这类耗时的任务而阻塞。这个线程通常称为主线程。
  • 异步执行任务的通常使用委托模式实现,也就协议传值
    • 比方写一个从URL中获取数据的嘞,使用委托模式设计
      请添加图片描述
    • 其他类像下面这样使用此类提供的API
      请添加图片描述
      这种做法可行,然而使用block块来写的话代码会更清晰。

块实现异步

  • 将一个方法定义为块类型当作参数传给某个方法
    请添加图片描述
    • 相比委托协议,块封装起来的时候可以在调用start方法时候以内联得形式定义completion handler,代码更加容易读懂
  • 委托模式还有缺点就是如果类分别使用多个获取器下载不同的数据,那么就得在delegate回调方法里根据传入参数切换
    请添加图片描述
  • 而使用块无需在回调方法里面切换,每个completion handler的逻辑都已经定义好了
    请添加图片描述

回调操作里的块

有时需要在相关事件点执行回调操作,这种情况也可以使用handler块。就比如说是下载应用的进度条。我们为其添加一个观察者,并且在其值发生改变的时候我们调用其中的块。
请添加图片描述

  • 此处传入的NSOperationQueue参数就表示触发通知时用来执行块代码的那个队列。这是个“队列操作”,而非“底层GCD队列” 这个在本章之后会学习到。

要点

  • 在创建对象时,可以使用内联的handler块将相关的业务逻辑一并声明。
  • 在有多个实例需要监控时,如果采用委托模式,那么经常需要根据传入的对象来切换,而若改用handler块来实现,则可以直接将块与相关对象放在一起。
  • 设计API时如果用到了handler块,那么可以增加一个参数,使用调用者可以通过此参数来决定应该把块安排在哪个队列上执行。

40.用块引用其所属对象时不要出现保留环

块中也存在保留环

  • 如果块所捕获的对象直接或间接的保留了块本身,那么就会出现一种相互引用的现象吗,也就是块中的保留环
    请添加图片描述
  • 保留环主要还是互相引用,尤其是在块的回调部分出现,可能你意识不到的时候就存在了保留环。
  • 只要合适的时候清除掉一方引用,就可以解决问题。
    请添加图片描述

要点

  • 如果块所捕获的对象直接或间接的保留了块本身,那么就得当心保留环问题。
  • 一定要找个适当的时机解除保留环,而不能把责任推给API的调用者。

总结

  • 前半章讲了块的主要内容,BLOCK,可以把代码像参数一样传递,其中传递的时候注意合理的时候typedef关键字和避免产生保留环

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/188547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

说说redux的实现原理是什么,写出核心代码?

目录标题一、redux三大基本原则是:二、实现原理:三、如何使用一、redux三大基本原则是: 单一数据源state是只读的使用纯函数来执行修改 注意的是,redux并不是只应用在react中,还与其他界面库一起使用,如V…

3.26 haas506 2.0开发教程-example- 串口控制ESP32-CAM OV2640拍照

haas506串口控制ESP32-CAM OV2640拍照介绍ESP32-CAM开发板硬件连接代码流程代码ESP32-CAM开发板代码HaaS506开发板代码测试ESP32-CAM开发板测试介绍 通过HaaS506串口发送指令,控制ESP32-CAM进行拍照,并将照片储存在SD卡中。ESP32-CAM需要5V供电才能正常…

小程序开发常见问题总结(超实用)

小程序开发常见问题总结(超实用) 文章目录小程序开发常见问题总结(超实用)1.小程序user agent stylesheet问题。2.this.setData is not function错误3.flex布局3.1flex布局原理3.2flex父项属性3.3flex布局子项元素4.自定义组件1.在…

白银k线图基础知识梳理:包覆形态

伦敦银价格走势是国际市场上所有参与者多方合力的结果,这些参与者包括银行、白银商、期货交易商、对冲基金等金融机构、各种法人机构以及个人投资者。一根简单的K线,能够把所有市场参与者博弈的结果展示出来,并且反映出银价运行和变化的各个细…

node后端接收到axios的post请求体为空

node后端接收到axios的post请求体为空??? 使用axios发送post请求,传入了Object格式的参数,在node后端req.body接收到的参数为空,但是网页上抓包检查时,发现请求的body确实是携带了参数的&#x…

【工具】2023开年利器,重写收藏逻辑和内置白板应用的Arc浏览器

目录一、为什么你需要一款新的浏览器?二、重写的收藏夹逻辑三、自带笔记和白板的浏览器四、如何获得Arc浏览器一、为什么你需要一款新的浏览器? 人生漫漫,三年混乱。在经历了这些起伏之后,你一定有一个不断进取的决心。 工欲善其…

如何设置将SAP红灯报错改为黄灯(OBA5 更改消息控制 )

在SAP的业务操作中或者后台配置经常遇到SAP校验报红灯的错误导致业务进行不下去。可以通过OBA5 更改消息控制事务修改消息报错类型,例如把红灯报错改为黄灯,这样业务就可以进行下去了。 举两个例子来说明一下如何配置。 目录 例子1:固定资…

【stl -- 内建函数对象】

目录:前言一、仿函数二、算数仿函数三、关系仿函数四、逻辑仿函数总结前言 概念 stl内建了一些仿函数 分类 算数仿函数、 关系仿函数、 逻辑仿函数 用法 这些仿函数所产生的对象,用法和普通函数完全一样; 使用内建仿函数需要包含头文件 一、…

拉伯证券|A股大涨!外资30分钟爆买百亿!汽车股狂飙

在很多利好音讯的轮番影响下,兔年首个交易日,A股迎来大涨。沪指开盘便站上3300点整数关口,尔后继续高位震动。深证成指、创业板指涨势更甚,到午盘涨幅均超1.5%。 外资继续“高调”抢筹。Choice数据显现,今天开盘仅5分…

Maven基础学习——依赖管理

本专栏主要是记录学习完JavaSE后学习JavaWeb部分的一些知识点总结以及遇到的一些问题等,如果刚开始学习Java的小伙伴可以点击下方连接查看专栏 本专栏地址:🔥JavaWeb Java入门篇: 🔥Java基础学习篇 Java进阶学习篇&…

18个 SpringBoot项目中遇到的BUG,你试试

有人说:一个人从1岁活到80岁很平凡,但如果从80岁倒着活,那么一半以上的人都可能不凡。 生活没有捷径,我们踩过的坑都成为了生活的经验,这些经验越早知道,你要走的弯路就会越少。 1.启动项目的时候报错 1.E…

从零到一,臻于至善|网易邮箱基于StarRocks 开发大数据平台的实践

作者:网易邮箱 黄贤康。现任职网易邮件事业部资深数据开发工程师,作为主要开发人员参与网易邮箱大数据平台的建立、优化、重构等工作,并取得相当的成效。他长期从事服务端应用及大数据领域的架构研发工作,对相关领域的底层架构、开…

什么是一站式人力资源管理系统?

首先什么是人力资源管理系统?简单来讲,人力资源管理系统就是帮助企业人力资源部门进行日常管理的辅助工具。人力资源部门通常需要负责企业员工管理的各个方面,无论是招聘,培训,考勤还是薪资绩效,都需要企业…

Jmeter使用手册

Jmeter使用手册Jmeter使用手册1.Jmeter安装教程下载地址Jmeter环境变量配置启动应用实例1.Jmeter安装教程下载地址https://jmeter.apache.org/download_jmeter.cgiJmeter环境变量配置新建变量名称:JMETER_HOME值为:D:\work_tools\apache-jmeter-5.5添加到path:%JMETER_HOME%\bi…

服务器应该如何做好防护以及被攻击之后如何处理

服务器是每个软件运行的基础,也是运行过程中最重要的一部分,所以在运行的过程中,服务器会受到黑客的不法攻击,那么服务器我们应该如何做好防护以防被攻击呢!接下来小蚁君给大家一一讲解。首先可以安装最新的安全补丁&a…

仪表板展示 | DataEase看中国:数据呈现中国能源发展情况

背景介绍 能源是经济发展的基石,能源的供给与人们生活和经济发展息息相关。二十大报告强调:“要积极稳妥推进碳达峰碳中和,立足我国能源资源禀赋,坚持先立后破,有计划分步骤地实施碳达峰行动。深入推进能源革命&#…

Elasticsearch使用篇 - 更新文档

更新的内部机制 注意:实际使用 murmurhash 算法 注意:更新任何一个字段都是全部删除。并发更新操作之间无事务隔离保证,会产生数据错位问题。 更新操作 1、单条覆盖更新 1、覆盖式更新,由客户端完成所有数据的组装,…

35. 实战:Python实现视频去水印(文末源码)

目录 前言 目的 思路 代码实现 1. 请求URL,查看源代码 2. 源代码中没有就去抓包工具 3. 拿到视频源链接,继续检索来源 4. 拿到数据和链接,二进制写入到本地 完整源码 运行效果 总结 前言 我们在刷某短视频平台时,有些…

SpringCloud搭建微服务之Vault密钥管理

1. 概述 Vault是一款管理密钥和保护敏感数据的组件,用于保护、存储和严格控制对令牌、密码、证书和加密密钥的访问,可以使用UI客户端、CLI和HTTP API访问密钥和其他敏感数据。更多详细介绍,可以参阅vault官网 2. Vault下载与安装 本文以wi…

【Python学习笔记】6. Python3 基本数据类型(下)——列表、元组、集合、字典、数据类型转换

前言 本文介绍Python3基本数据类型——列表、元组、集合、字典、数据类型转换。 List(列表) List(列表) 是 Python 中使用最频繁的数据类型。 列表可以完成大多数集合类的数据结构实现。列表中元素的类型可以不相同&#xff0…