【iOS】系统框架

news/发布时间2024/5/14 19:52:58

文章目录

  • 前言
  • 四十七、熟悉系统框架
  • 四十八、多用块枚举,少用for循环
  • 四十九、对自定义其内存管理语义的collection使用无缝桥接
  • 五十、构建缓存时选用NSCache而非NSDictionary
  • 五十一、精简initialize与load的实现代码
  • 五十二、别忘了NSTimer会保留其目标对象


前言

本次博客撰写小蓝书的最后一章系统框架

四十七、熟悉系统框架

OC的Foundation框架,像NSObject NSArray, NSDictionary等类都在其中。Foundation框架里的类都是用NS前缀,因为OC之前作为NeXTSTEP操作系统确定的。

将一系列代码封装为动态库,并在其中放入描述其接口的头文件,这样做出来的东西就叫框架。

CoreFoundation框架

Foundation框架提供了collection等基础核心功能,而且还提供了字符串处理等复杂功能。还存在一个CoreFoundation框架,在之前了解过他是不属于OC框架之内的,但是OC应用程序的编写离不开这个框架,Foundation框架的许多功在CoreFoundation框架都可以找到对应的C语言API

他其中的很多类都和Foundation框架相似,并且我们还可以通过“无缝桥接”功能实现CoreFoundation框架中的C语言数据结构平滑转换为Foundation框架中的OC对象,也可以反向转换。无缝桥接技术是用某些相当复杂的代码实现出来的,这些代码可以使运行期系统把CoreFoundation框架中的对象视为普通的OC对象。

NSString所对应的就是CFString对象。

其他框架:
在这里插入图片描述
OC编程的重要特点就是:经常需要使用底层的C语言级 API。用c语言实现 API的好处是,可以统过 Objeotive-C 的运行期系统,从而提升执行速度

要点

  • 许多系统框架都可以直接使用。其中最重要的是Foundation与CoreFoundation,这两个框架提供了构建应用程序所需的许多核心功能。
  • 很多常见任务都能用框架来做,例如音频与视频处理、网络通信、数据管理等。
  • 请记住:用纯C写成的框架与用OC写成的一样重要,若想成为优秀的OC开发者,应该掌握C语言的核心概念。

四十八、多用块枚举,少用for循环

语言中引人“块” 这一特性后,又多出来儿种新的通历方 式,而这几种方式容易为开发者所忽视。采用这几种新方式遍历collection 时,可以传人块, 而collection 中的每个元素都可能会放在块里运行一遍,这种做法通常会大幅度简化编码过程以下进行各种遍历方法详细说明:

for循环
在这里插入图片描述
根据定义,因为字典与set对象是无需的,所以无法通过下标访问,所以需要先获取字典里的所有键值或是set中的所有对象,这两种情况下都可以放到数组中实现,就如上述代码所显示

NSEnumerator遍历
NSEnumerator是个抽象基类,其中只定义了两个方法,供其具体子类来实现:
在这里插入图片描述
关键的是其中的nextObject对象,它返回枚举里的下个对象,当返回不为nil的时候就会一直调用下一个对象,常用while语句

对于set与字典写法其实也与标准的for循环相似,只是代码多了一些,其优势在于无论遍历哪一种collection,都可以采用这套相似的语法
在这里插入图片描述

快速遍历
快速遍历是OC2.0引入的语法功能,引入了in关键字,语法更加简洁了collection的遍历过程。尤其是字典类
在这里插入图片描述

基于块的遍历方式
在这里插入图片描述
参数1是每次枚举的对象, idx是下标, stop则是代表是否停止遍历

使用这种方法遍历时既能获取对象,也能知道其下标

    [t enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {NSLog(@"%@ %lu", obj, (unsigned long)idx);      }];

对于字典,还可获得其key与object
在这里插入图片描述

此方式大大胜; 过其他 方式的地方在于:遍历时可以直接从块里获取更多信息。在遍历数 组时,可以知道当前所针对的下标。遍历有序set (
NSOrderedset )时也一样。而在遍历字典 时, 无须额外编码,即可同时获取键与值,因而省去了根据给定键来获取对应值这一步。用
这种方式遍历字典,可以同时得知键与值,这很可能比其他方式快很多,因为在字典内部的 数据结构中,键与值本来就是存储在一起的。

在这里插入图片描述
同时还可通过选项掩码进行反向遍历

要点

  • 遍历collection有四种方式。最基本的办法是for循环,其次是NSEnumerator遍历法及快速遍历法,最新、最先进的方式则是“块枚举法”。
  • “块枚举法”本身就能通过GCD来并发执行遍历操作,无须另行编写代码。而采用其他遍历方式则无法轻易实现这一点。
  • 若提前知道待遍历的collection含有何种对象,则应修改块签名,指出对象的具体类型

四十九、对自定义其内存管理语义的collection使用无缝桥接

Objective-C的系统库包含相当多的collection 类,其中有各种数组、各种字典、各种 setoFoundation框架定义了这些collection及其他各种collection所对应的Objective-C类 。与 之相似,CoreFoundation 框架也定义了一套C语言API,用于操作表示这些collection 及其他 各种collection 的数据结构。

例如,NSAray 是Foundation 框架中表示数组的Objective-C类, 而CFArray 则是CoreFoundation 框架中的等价物。这两种创建数组的方式也许有区别,然而 有 项 强 大 的 功 能 可 在 这 两 个 类 型 之 间 平 滑 转 换, 它 就 是 “ 无 缝 桥 接” ( t o l l - f r e e b r i d g i n g ) 。

转换操作中的__bridge告诉ARC如何处理转换所涉及的OC对象。__bridge本身的意思是:ARC仍然具备这个OC对象的所有权。而__bridge_retained则与之相反,意味着ARC将交出对象的所有权。与之相似,反向转换可通过__bridge_transfer来实现,也就是将对象的所有权交给ARC。这三种转换方式称为“桥式转换”

- (void)seamlessBridging {NSArray *testArray = @[@"111", @"222", @"333",];CFArrayRef aCFArray = (__bridge  CFArrayRef)testArray;NSLog(@"cfArratSize =  %li", CFArrayGetCount(aCFArray));
}

要点

  • 通过无缝桥接技术,可以在Foundation框架中的OC对象与CoreFoundation框架中的C语言数据结构之间来回转换。
  • 在CoreFoundation层面创建collection时,可以指定许多回调函数,这些函数表示此collection应如何处理其元素。然后,可运用无缝桥接技术,将其转换成具备特殊内存管理语义的OC collection。

五十、构建缓存时选用NSCache而非NSDictionary

开 发 M a c O s × 或 i 0 s 应 用 程 序 时 , 经 常 会 遇 到 一个 问 题 , 那 就 是 从 因 特 网 下 载 的 图 片 应如何来缓存。首先能想到的好办法就是把内存中的图片保存到字典里,这样的话,稍后使 用 时 就 无 须 再 次 下 载 了。 有 些 程 序 员 会 不 假 思 索 , 直 接 使 用 N S D i c t i o n a r y 来 做 (准 确 来 说 , 是使用其可变版本),因为这个类很常用。其实,NSCache 类更好,它是Foundation 框架专 为处理这种任务而设计的。

NSCache 胜过NSDictionary 之处在于,当系统资源將要耗尽时,它可以自动删减缓存
另外,NSCache 是线程安全的。 而NSDictionary 则绝对不具备此优势

要点

  • 实现缓存时应选用NSCache而非NSDictionary对象。因为NSCache可以提供优雅的自动删减功能,而且是“线程安全的”,此外,它与字典不同,并不会拷贝键。
  • 可以给NSCache对象设置上限,用以限制缓存中的对象总个数及“总成本”,而这些尺度则定义了缓存删减其中对象的时机。但是绝对不要把这些尺度当成可靠的“硬限制”,它们仅对NSCache起指导作用。
  • 将NSPurgeableData与NSCache搭配使用,可实现自动清除数据的功能,也就是说,当NSPurgeableData对象所内存为系统所丢弃时,该对象自身也会从缓存中移除。
  • 如果缓存使用得当,那么应用程序的响应速度就能提高。只有那种“重新计算起来很费事的”数据,才值得放入缓存,比如那些需要从网络获取或从磁盘读取的数据。

五十一、精简initialize与load的实现代码

在OC里一个类必须初始化才能使用,大多数类继承与NSObject这个根类,提供了loadinitalize方法

load
加入运行期系统中的每个类和分类来说,会调用此方且仅调用一次,当类和分类的程序载入系统的时候就会执行这个方法,调用顺序是类大于分类

总结一句话就是不要用load

initalize
该方法是在程序首次使用该类之前调用且仅有一次,是由运行期系统调用的,不通过代码调用。和load存在区别

  • 惰性调用当程序用到了相关类的时候才会调用,类似于懒加载模式。而load是所有类不管用不用先load方法之后再说
  • 其次运行期在执行该方法的时候是系统正常状态,也就是安全状态,不影响调用类的其他方法,此为线程安全。
  • 当某个类没实现initialize方法,超类实现后会调用超类的方法,和大多数消息是一样的。

initalize方法尽量精简

  • 首先,大家都不想看到自己的应用程序“挂起”,若写的太过繁琐,导致其运行很慢那就适得其反了。
  • 开发者无法控制类的初始化时机。
  • 最后,如果某个类的实现代码很复杂,那么其中可能会直接或间接用到其他类。若那些类尚未初始化,则系统会迫使其初始化。然而,本类的初始化方法此时尚未运行完毕。其他类在运行其initialize方法时,有可能会依赖本类中的某些数据,而这些数据此时也许还未初始化好,就会造成依赖环

initalize方法只应该用来设置内部数据,不能在内部调用其他的方法。

initalize还可以初始化某个无法在编译器初始化的全局变量
在这里插入图片描述
但别忘了单例类也可以实现该目的

要点

  • 在加载阶段,如果类实现了load方法,那么系统就会调用它。分类里也可以定义此方法,类的load方法要比分类中的先调用。与其他方法不同,load方法不参与覆写机制。
  • 首次使用某个类之前,系统会向其发送initialize消息。由于此方法遵从普通的覆写规则,所以通常应该在里面判断当前要初始化的是那个类。
  • load与initialize方法都应该实现的精简一些,这有助于保持应用程序的响应能力,也能减少引入“依赖环”的几率。
  • 无法在编译期设定的全局常量,可以放在initialize方法里初始化。

五十二、别忘了NSTimer会保留其目标对象

Foundation框架中有个类叫NSTimer,开发者可以指定绝对的日期与时间,以便到时执行任务,计时器要和“运行循环(run loop)”相关联,运行循环到时候会触发任务。创建NSTimer时,可以将其“预先安排”在当前的运行循环中,也可以先创建好,然后由开发者自己来调度。无论采用哪种方式,只有把计时器放在运行环里,它才能正常触发任务

创建计时器

 _pollTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(pDoPoll) userInfo:nil repeats:YES];

保留环

创建计时器的时候,由于目标对象是self,所以要保留此实例。然而,因为计时器是用实例变量存放的,所以实例也保留了计时器,于是,就产生了保留环。所以说,调用stopPolling,或者令系统将此实例回收,只有这样才能打破保留环。

因为是类和这个类中的实例出现了保留环,不管你外界怎么对这个类释放,这个计时器始终都会保留这个类,而这个类也会保留这个计时器,互相引用保留导致他们的计数永远都不会降为0

在这里插入图片描述
如果从外界直接先调用stop方法,代码没办法自己检测。

使用块的特点打破保留环

使用块和weak关键字合理的打破保留环,块可以传递代码,这一功能可以利用
在这里插入图片描述
在这里插入图片描述
这个办法为何能解快“ 保留环〞问题呢?大家马上就会明白。这段代码将计时器所应执 行的任务封装成“ 块”,在调用计时器西数时,把它作为userlnfo 参数传进去。该参数可用来 存 放 “ 不 透 明 值 ” ( o p a q u e v a l u e )。 , 只 要 计 时 器 还 有 效 , 就 会 一直 保 留 着 它 。 传 人 参 数 时 要 通 过copy方法将block拷贝到“堆” 上(之前在blk提过,copy方法把块变成了有引用计数的对象。),否则等到稍后要执行它的时候,该块 可能己经无效了。计时器现在的target 是NSTimer 类对象,这是个单例,因此计时器是否会 保 留 它, 其 实 都 无 所 谓 。 此 处 依 然 有 保 留 环 , 然 而 因 为 类 对 象 ( c l a s s o b j e c t ) 无 须 回 收 , 所 以 不用担心。

此处依然有保留环,使用weak关键字打破它
在这里插入图片描述
这 段 代 码 采 用 了一 种 很 有 效 的 写 法 , 它 先 定 义 了一 个 弱 引 用 , 令 其 指 向 s e l f , 然 后 使 块 捕获这个引用,而不直接去捕获普通的sel f 变量。也就是说,sel f 不会为计时器所保留。当 块开始执行时,立刻生成strong 引用,以保证实例在执行期间特续存活。

采用这种写法之后,如果外界指向EOCClass实例的最后 一个引用将其释放,则该实例 就 可 为 系 统 所 回 收 了。

要点

  • NSTimer对象会保留其目标,直到计时器本身失效为止,调用invalidate方法可令计时器失效,另外,一次性的计时器在触发完成任务之后也会失效。
  • 反复执行任务的计时器,很容易引人保留环,如果这种计时器的目标对象又保留了计时器本身,那肯定会导致保留环。这种环状保留关系,可能是直接发生的,也可能是通过对象图里的其他对象间接发生的。
  • 可以扩充NSTimer的功能,用“块” 来打破保留环。不过,除非NSTimer将来在公共接口里提供此功能,否则必须创建分类,将相关实现代码加入其中。

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

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

相关文章

element-UI 组件 dialog 中 ref 获取不到元素

项目场景: vue3集成bpmn.js 渲染过程中,进行流程图查看 问题描述 dialog弹窗加载获取canvas中 加载不到,导致偶尔流程展示加载失败 原因分析: 提示:官方解释如下,主要就是获取的时候,组件没有…

VScode中配置 C/C++ 环境 | IT拯救者

文章目录 0 引言1. 下载编辑器VScode2. 下载编译器MinGW并解压3. 将MinGW添加至环境变量4. 配置VScode插件5. 运行代码6. 调整和优化7. 提示8. 例行格式条款9. 例行格式条款 0 引言 由于VScode毛毛张使用不习惯,因此配置教程记不住,不过毛毛张看到一篇不…

接口测试总结及其用例设计方法

接口测试的总结文档 第一部分:主要从问题出发,引入接口测试的相关内容并与前端测试进行简单对比,总结两者之前的区别与联系。但该部分只交代了怎么做和如何做?并没有解释为什么要做? 第二部分:主要介绍为什…

C语言----内存函数

内存函数主要用于动态分配和管理内存,它直接从指针的方位上进行操作,可以实现字节单位的操作。 其包含的头文件都是:string.h memcpy copy block of memory的缩写----拷贝内存块 格式: void *memcpy(void *dest, const void …

Leo赠书活动-16期 名校毕业生教材

Leo赠书活动-16期 名校毕业生教材 ✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 赠…

LeetCode JS专栏刷题笔记(一)

一、前言 LeetCode 在前不久出了一个 JavaScript 专栏,这个专栏一个目的是为了非前端工程师学习 JS,另一个是为了前端工程师提升 JS 能力。 因此在这个专栏中,基本不涉及什么具体算法问题,都是一些 JS 的入门语法与常见的 JS 面…

Android13 针对low memory killer内存调优

引入概念 在旧版本的安卓系统中,当触发lmk(low memory killer)的时候一般认为就是内存不足导致,但是随着安卓版本的增加lmk的判断标准已经不仅仅是内存剩余大小,io,cpu同样会做评判,从而保证设备…

基于 Python 深度学习的电影评论情感分析系统,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

总结:Mybatis报错Invalid bound statement (not found)

目录 1、Mapper.xml中mapper namespace路径不准确 2、TextDao&#xff08;接口&#xff09;与TextMapper.xml id标签不一致 ​编辑 3、application.properties中配置mybatis.type-aliases-packagecom.demo.entity需要与Text实体类路径一致 4、pom.xml文件中需要配置<res…

adobe软件提示This non-genuine Adobe app will be disabled soon【软件版本】

因为电脑上级路由器装了小飞机&#xff0c;导致本机电脑ps等adobe的系列软件出现了 This non-genuine Adobe app will be disabled soon&#xff0c;烦人的狠&#xff0c;之前有写过一篇通过更改host的教程&#xff0c;现在已经失效了&#xff0c;今天为大家分享一个用软件来屏…

关于数据结构的定义以及基本的数据结构

在计算机科学中&#xff0c;数据结构是指用于组织和存储数据的方式或方法。它涉及到在计算机内存中存储、管理和操作数据的技术和原则。数据结构不仅仅是简单地存储数据&#xff0c;还可以提供高效的数据访问和操作方式&#xff0c;以满足特定的需求。 以下是每个数据结构的详细…

ubuntu屏幕小的解决办法

1. 安装vmware tools , 再点自适应客户机 执行里面的vmware-install.pl这个文件 &#xff1a;sudo ./vmware-install.pl 执行不了可以放到家目录&#xff0c;我放在了/home/book 里面 最后点这个自适应客户机 然后我这里点不了是因为我点了控制台视图和拉伸客户机&#xff0c…

个人简历补充

个人简历补充 1.对工作的认识2.八股文和知识面3.框架/架构角度深扒3.1 前端3.1.1 mPaaS&#xff08;移动领域&#xff09;3.1.2 普通前端项目框架3.1.3 微前端 3.2 后端 持续更新 1.对工作的认识 2.八股文和知识面 前端&#xff08;基础知识 / 开发能力 / 总结输出能力&#xf…

electron桌面开发相关注意点

electron的部署以及配置 如果使用的是pnpm&#xff0c;请先配置一下镜像&#xff0c;否则会安装失败的&#xff1a; pnpm config set registryhttps://registry.npmmirror.com pnpm config set electron_mirrorhttps://cdn.npmmirror.com/binaries/electron/ pnpm config set …

【Linux】进程间通信——共享内存

文章目录 共享内存的概要创建共享内存shmget()参数keyshmget()参数sizeshmget()参数shmflg 删除共享内存挂载共享内存去关联 共享内存的概要 共享内存允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间传递数据的一种非常有效的方式。不同进程之间…

用阿里云一键部署了幻兽帕鲁服务器,怎么一键切换成雾锁王国服务器?

之前用阿里云一键部署的幻兽帕鲁服务器&#xff0c;现在不想玩了&#xff0c;想要换成雾锁王国服务器&#xff0c;该怎么操作呢&#xff1f; 操作方法如下&#xff1a; 首先打开你的阿里云计算巢&#xff0c;之前你买过的一键部署幻兽帕鲁服务实例&#xff0c;这里应该可以看…

Ansible的脚本 --- playbook 剧本

目录 playbook的简介 什么是playbook playbook组成 应用实例 Templates 模块 tags 模块 Roles 模块 playbook的简介 什么是playbook Ansible Playbook 是设定自动化任务的一种蓝图&#xff0c;可在无需人工干预或有限干预的前提下执行复杂的 IT 操作。Ansible Playboo…

Zig、C、Rust的Pk1

Zig、C、Rust的Pk1 github.com上看到“A basic comparitive analysis of C, C, Rust, and Zig.”&#xff1a;https://github.com/CoalNova/BasicCompare/tree/main 里边的代码是9个月之前的&#xff0c;用现在的zig 0.11.0 及0.12-dev都无法通过编译(具体为&#xff1a;zig-w…

【MATLAB源码-第140期】基于matlab的深度学习的两用户NOMA-OFDM系统信道估计仿真,对比LS,MMSE,ML。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 深度学习技术在无线通信领域的应用越来越广泛&#xff0c;特别是在非正交多址接入&#xff08;NOMA&#xff09;和正交频分复用&#xff08;OFDM&#xff09;系统中&#xff0c;深度学习技术被用来提高信道估计的性能和效率。…

【JavaEE】_CSS选择器

目录 1. 基本语法格式 2. 引入方式 2.1 内部样式 2.2 内联样式 2.3 外部样式 3. 基础选择器 3.1 标签选择器 3.2 类选择器 3.3 ID选择器 4. 复合选择器 4.1 后代选择器 4.2 子选择器 4.3 并集选择器 4.4 伪类选择器 1. 基本语法格式 选择器若干属性声明 2. 引入…
推荐文章