【Effective Objective - C】—— block 块

【Effective Objective - C】—— block 块

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

前言

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

37.理解块的概念

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

块的基础知识

块与函数类似,只不过是直接定义在另一个函数里的,和定义它的那个函数共享同一个范围内的东西。块用“^”符号来表示,后边跟着一对花括号,括号里面是块的实现代码。

^{block implementation 
}

块也是一个值,它的语法和函数类似,语法结构如下:

return_type (^block_name)(parameters)

具体实例,这是定义一个名字为addBlock的块变量,可以类似于函数去使用它

#import <Foundation/Foundation.h>
NSString* (^addBlock)(NSString *a, NSString* b) = ^(NSString *a, NSString* b) {return [NSString stringWithFormat:@"%@%@", a, b];
};
int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...NSString* new = addBlock (@"3g", @"iOS");NSLog(@"new = %@", new);}return 0;
}

在这里插入图片描述

块可以捕获变量

块可以在它生命的范围里面所有变量都可以捕获。

#import <Foundation/Foundation.h>
NSString* c = @"ff";
NSString* (^addBlock)(NSString *a, NSString* b) = ^(NSString *a, NSString* b) {return [NSString stringWithFormat:@"%@%@%@", a, b, c];
};
int main(int argc, const char * argv[]) {@autoreleasepool {// insert code here...NSString* new = addBlock (@"3g", @"iOS");NSLog(@"new = %@", new);}return 0;
}

在默认情况下我们捕获的C字符串是不可以修改的,不过声明变量的时候加入__block即可在块内修改。

#import <Foundation/Foundation.h>int main(int argc, const char * argv[]) {__block NSString* c = @"ff";NSString* (^addBlock)(NSString *a, NSString* b) = ^(NSString *a, NSString* b) {c = @"1234";return [NSString stringWithFormat:@"%@%@%@", a, b, c];};@autoreleasepool {// insert code here...NSString* new = addBlock (@"3g", @"iOS");NSLog(@"new = %@", new);}return 0;
}

在这里插入图片描述

内联块的用法

如果块所捕获的变量是对象类型,那么就会自动保留它。系统在释放这个块的时候,也会将其一并释放。这就引出了一个于块有关的重要问题。块本身可视为对象。并且块本身也和其他对象一样,有引用计数。如果将块定义在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的调用者。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot项目快速创建

SpringBoot项目快速创建 方法一&#xff1a;通过IDEA的Spring Initializr 点击文件&#xff0c;新建项目&#xff0c;选择Spring Initializr 名称&#xff1a;项目名称存放位置&#xff1a; 语言&#xff1a;Java类型&#xff1a;Maven组&#xff1a;<groupId>com.exam…

MyBatisPlus条件构造器和常用接口

前置配置文章 一、wapper介绍 wrapper的继承体系&#xff1a; Wrapper &#xff1a; 条件构造抽象类&#xff0c;最顶端父类 AbstractWrapper &#xff1a; 用于查询条件封装&#xff0c;生成 sql 的 where 条件 QueryWrapper &#xff1a; 查询条件封装UpdateWrapper &#x…

【MATLAB GUI】 4. 坐标区和表

看B站up主freexyn的freexyn编程实例视频教程系列36Matlab GUI的学习笔记 文章目录 坐标区表 坐标区 任务要求设计一个图像显示界面&#xff0c;根据选定的周期做出相应的sin函数图像 使用坐标区、弹出式菜单、普通按钮设计页面&#xff0c;弹出式菜单string设置为1、2、3、4代…

C#,动态规划(DP)丢鸡蛋问题(Egg Dropping Puzzle)的三种算法与源代码

1 扔鸡蛋问题 动态规划&#xff08;Dynamic Programming&#xff0c;DP&#xff09;是运筹学的一个分支&#xff0c;是求解决策过程最优化的过程。20世纪50年代初&#xff0c;美国数学家贝尔曼&#xff08;R.Bellman&#xff09;等人在研究多阶段决策过程的优化问题时&#xf…

【MySQL】数据库概述

目录 一、为什么使用数据库&#xff1f; 二、数据库与数据库管理系统 2.1 相关概念 2.2 两者关系 三、 MySQL介绍 四、 RDBMS和非RDBMS 4.1 关系型数据库&#xff08;RDBMS&#xff09; 4.2 非关系型数据库&#xff08;非RDBMS&#xff09; 五、关系型数据库设计规则 …

WebService学习,wsdl文件详解

目录 第一章、起因1.1&#xff09;学习原因1.2&#xff09;提问的过程&#xff08;逐步提出问题&#xff09;1、&#xff1f;wsdl链接的含义&#xff0c;有什么作用&#xff1f;2、什么是wsdl文档&#xff1f;3、如何阅读wsdl文件&#xff1f;4、wsdl文件有什么作用&#xff1f…

百面嵌入式专栏(经验篇)如何在面试中介绍自己的项目经验

文章目录 1. 在面试前准备项目描述,别害怕,因为面试官什么都不知道2. 准备项目的各种细节,一旦被问倒了,就说明你没做过3.不露痕迹地说出面试官爱听的话4.一定要主动,面试官没有义务挖掘你的亮点5.一旦有低级错误,可能会直接出局6.引导篇:准备些加分点,在介绍时有意提到…

图文说明Linux云服务器如何更改实例镜像

一、应用场景举例 在学习Linux的vim时&#xff0c;我们难免要对vim进行一些配置&#xff0c;这里我们提供一个vim插件的安装包&#xff1a; curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o./install.sh && bash ./install.sh 但是此安装包…

关于el-select值的回显问题 : 框内显示label值还是value值

<el-form-item label"状态" prop""><el-selectv-model"roleForm.state"class"m-2"size"large"style"width: 240px"placeholder"请选择状态"value-key"value"//value-key 与下面的ke…

区块链笔记(五)---德勤相关分析报告

web3.0 定义&#xff1a; 在《Insights into a Modern World》提出&#xff0c;“信息将由用户自己发布、保管、不可追溯且永远不会泄露&#xff0c;用户的任何行为将不需要任何中间机构来帮助传递”&#xff1b;用来指代一种区块链技术&#xff0c;可以基于“无须信任的交互…

探索D咖智能饮品机器人的工作原理:科技、材料与设计的相互融合

智能饮品机器人是近年来随着人工智能和自动化技术的发展而崭露头角的一种创新产品。它将科技、材料和设计相互融合&#xff0c;为消费者带来了全新的饮品体验。下面D咖来探索智能饮品机器人的工作原理&#xff0c;以及科技、材料和设计在其中的作用。 首先&#xff0c;智能饮品…

STM32—触摸键

目录 1 、 电路构成及原理图 2 、编写实现代码 3、代码讲解 4、烧录到开发板调试、验证代码 5、检验效果 此笔记基于朗峰 STM32F103 系列全集成开发板的记录。 1 、 电路构成及原理图 触摸键简单的了解就是一次电容的充放电过程。从原理图可以看出&#xff0c;触摸键 …

钧达股份:光伏跨界新贵只身赴港股,光伏“秩序重塑”?

2月21日&#xff0c;钧达股份终是在“千呼万唤”之中披露最新业绩快报。 快报显示&#xff0c;钧达股份预计2023年经调整后营业收入183.97亿元&#xff0c;同比增长58.65%&#xff0c;归母净利润8.32亿元&#xff0c;同比增长16.00%。 其中&#xff0c;由于Q4完整计提了9.5GW…

c语言经典测试题3

1.题1 int a 248, b 4; int const *c 21; const int *d &a; int *const e &b; int const * const f &a; 请问下列表达式哪些会被编译器禁止&#xff1f; A: *c 32; B: *d 43 C: e&a D: f0x321f 我们来分析一下&#xff1a;const用来修饰变量是想其…

遍历的三种算法——递归、非递归、层次

一、递归遍历方法&#xff1a; 先序遍历&#xff1a; Status PreOrderTraverse(Tree *t) {if (t NULL) return OK;//合法性检查else {visit(t->data);//访问根节点PreOrderTraverse(t->lchild);//递归遍历左子树PreOrderTraverse(t->rchild);//递归遍历右子树} } …

【ArcGIS】利用高程进行坡度分析

在ArcGIS中利用高程进行坡度分析 坡度ArcGIS实操参考 坡度 坡度是地表单元陡缓的程度&#xff0c;通常把坡面的垂直高度和水平距离的比值称为坡度。 坡度的表示方法有百分比法、度数法、密位法和分数法四种&#xff0c;其中以百分比法和度数法较为常用。 &#xff08;1&#…

C语言特殊函数

静态函数 背景知识&#xff1a;普通函数都是跨文件可见的&#xff0c;即在文件 a.c 中定义的函数可以在 b.c 中使用。 静态函数&#xff1a;只能在定义的文件内可见的函数&#xff0c;称为静态函数。 语法 staitc void f(void) // 在函数头前面增加关键字 static &#xff…

智慧城市的新宠儿:会“思考”的井盖

在城市化飞速发展的今天&#xff0c;我们或许未曾过多地关注那些平凡却至关重要的井盖。它们无声地矗立在城市的每个角落&#xff0c;守护着深藏于地下的城市生命线&#xff0c;然而&#xff0c;这些井盖并未满足于传统的角色&#xff0c;它们正逐步融入智慧城市的宏大画卷中&a…

IDEA生成Java Doc帮助文档

使用场景 使用IDEA&#xff08;本次使用2020.3版&#xff09;将自己写的常用的工具类打成jar包&#xff0c;安装到maven本地仓库&#xff0c;最后生成对应的doc参考文档。 操作流程 方法一 选中项目 右键 show in Explor&#xff0c;如下图&#xff1a; 选中地址栏 cmd 输入…

Android约束布局中用ConstraintHelper实现过渡动画效果

前些天发现了一个蛮有意思的人工智能学习网站,8个字形容一下"通俗易懂&#xff0c;风趣幽默"&#xff0c;感觉非常有意思,忍不住分享一下给大家。 &#x1f449;点击跳转到教程 一.创建一个类CircularRevealHelper继承ConstraintHelper代码如下 /*** Author: ly* Da…