iOS多线程-GCD

前言 Hi Coder,我是 CoderStar! 今天给大家带来多线程系列的第二篇文章 – GCD,其大概率是我们在使用多线程时最常用的方式了。 GCD 全称是 Grand Central Dispatch,翻译过来就是大规模中央调度。根据官方文档,它的作用是:通过向系统管理的调度队列中提交任务,在多核硬件上同时执行代码。它提供了一套机制,让你可以充分利用硬件的多核性能,并且让你不用再调用那些繁琐的底层线程 API,编写易于理解和修改的代码。 对开发者而言,面对的不再是上一篇文章 iOS多线程-Thread 所描述的线程,CGD 将线程概念模糊掉,开发者转而面对的是更上层的队列和任务,不再需要考虑线程的周期以及调度等等,这些交由 GCD 内部处理就好。 本文对一些概念性的东西可能会一笔带过,主要介绍日常开发的一些经验。同时更多细节大家可以看苹果开源出来关于 GCD 的源码 –swift-corelibs-libdispatch,同时我们通过源码也能了解到 GCD 的底层 API 都是用 C 写的。 队列 一般情况下我们可以将队列分为串行和并行两种,其中主队列是一种特殊的串行队列,全局队列是一组特殊的并行队列。 构造函数 下列为队列的构造函数 1 2 3 4 5 public convenience init(label: String, qos: DispatchQoS = .unspecified, attributes: DispatchQueue.Attributes = [], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = .inherit, target: DispatchQueue? = nil) 介绍一下各个参数的作用: ...

November 16, 2024 · 5 min · 1017 words · CoderStar

iOS多线程-Operation

前言 Hi Coder,我是 CoderStar! 我们之前已经讲过 iOS多线程-Thread 以及 iOS多线程-GCD,我们今天来聊一聊 iOS 多线程中最后一种比较常用的方式 –Operation。 概览 对于 Operation 而言,其相关的类比 GCD 要少的多。Operation 本身是一个 抽象类,不能直接进行使用,其定义了相关的方法及属性,需要靠子类进行相应的实现,系统已经实现了一个 –BlockOperation。(在 OC 中,还有一个是 NSInvocationOperation,但在 Swift 中,该子类已经在 Swift4 里去掉,想必去掉的原因大家也很容易理解,因为 Swift 语言本身就不推荐 selector 这种形式)。 Operation 底层建立在 GCD 之上,是更高一级的抽象,使我们可以面向对象(Cocoa 对象)的方式进行多线程编程。 其实 NSOpertion 是先于 GCD 引进的,在当时,NSOperationQueue 接收 NSOperation 对象并创建一个线程,然后在该线程上运行 main 方法 ,运行完成之后再杀死该线程。这种方式相对于后面出现的 GCD 底层的线程池而言,效率就很低,所以在 Mac OS 10.5 以及 iOS 2 开始便对 NSOpertion 底层在基于 GCD 的基础上进行完全重写,利用 GCD 的相关特性提高性能并提供了一些新功能。如果想简单佐证下,可以看到 OperationQueue 拥有一个 unowned(unsafe) open var underlyingQueue: DispatchQueue? 属性。 如果大家对 Operation 底层实现比较有兴趣,可以在开源的 Foundtion 框架中查看 Operation.swift。 ...

November 16, 2024 · 6 min · 1080 words · CoderStar

iOS多线程-Thread

前言 Hi Coder,我是 CoderStar! 多线程是 iOS 中一个重要的知识点,常见的技术包含 Thread GCD Operation Pthreads 其中前三种方式我们比较常用,其中 GCD、Operation 使用的最频繁。Pthreads 是基于 C 语言的框架,可以跨平台使用,我们平时使用比较少。 作为多线程系列的开篇,今天我们先来讲讲 Thread,虽然它用的比较少也比较简单,但还是需要我们掌握了解的。 Thread 相对 GCD、Operation 而言使用起来比较轻量级。其管理的基本单位就是线程,每一个 Thread 都对应一个线程。 需要自己管理线程的生命周期、线程同步、加锁、睡眠以及唤醒等。 Thread 的创建方式 Thread 的创建有多种方式。 类方法 1 2 3 4 @available(iOS 10.0, *) open class func detachNewThread(_ block: @escaping () -> Void) open class func detachNewThreadSelector(_ selector: Selector, toTarget target: Any, with argument: Any?) 类方法创建的线程自动运行,通过这种方式我们无法对 Thread 属性进行一些自定义的设置,如 name、threadPriority 等。 ...

November 16, 2024 · 2 min · 359 words · CoderStar

设计模式-责任链模式&策略模式~扫码场景下的落地

前言 Hi Coder,我是 CoderStar! 今天主要是给大家分享一下两种设计模式,即责任链模式以及策略模式。至于为什么想着给大家分享这两种设计模式呢,这源于我之前对扫码场景的相关代码优化,下面我将结合我遇到这个的场景给大家讲一下这两种设计模式。 顺便我也表达一点我对设计模式的看法,设计模式需要结合一定的使用场景才会体现才会它的妙处,大家在平时在开发时觉得哪些地方的代码不简洁优雅,都可以思考一下应用哪种设计模式可以对其进行优化、解耦,但也需要注意,不要对设计模式生搬硬套。 同时本篇文章也将是设计模式系列的开篇作了,后面也会慢慢给大家介绍其他的设计模式及其应用的场景。 场景及一般实现 有一个场景,想必大家都遇到过,就是扫描不同的二维码根据扫描结果跳转进入到不同的功能页面,如登录、加好友等等。我们拿到结果后需要对内容进行校验,是否是我们需要的信息,然后做一些特殊的处理。比如先判断是不是一个 url 链接,是则打开这个链接,不是的话进行下一种判断,比如是否是项目中的约定的跳转某个功能的信息… 依次下去。 因代码篇幅,后面代码示例也只体现登录、加好友两个 case。 普通的写法便是通过 if-else 或者 switch-case 对条件进行判断继而执行不同的分支。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 func onScanResult(type: String) { switch type { case "login": // TODO 登录的相关逻辑 case "addContacts" // TODO 添加联系人的相关逻辑 // 此处省略99种分支判断 ... default: break } } 上述示例逻辑相对简单,可推理到业务,有可能登录、添加联系人内部逻辑都很复杂,并且还有可能分支判断不是简单的根据 type 来判断,而是根据很多条件综合来判断。 ...

November 16, 2024 · 4 min · 665 words · CoderStar

Swift开发规范

前言 代码的字里行间流淌的是软件生命中的血液,质量的提升是尽可能少踩坑,杜绝踩重复的坑,切实提升质量意识。另外,现代软件架构都需要协同开发完成,高效协作即降低协同成本,提升沟通效率,所谓无规矩不成方圆,无规范不能协作。众所周知,制订交通法规表面上是要限制行车权,实际上是保障公众的人身安全。试想如果没有限速,没有红绿灯,谁还敢上路行驶。对软件来说,适当的规范和标准绝不是消灭代码内容的创造性、优雅性,而是限制过度个性化,以一种普遍认可的统一方式一起做事,提升协作效率。– 摘自《阿里巴巴 Java 代码规范》 该开发规范会持续更新,请关注该 博文链接。 规约分为【强制】、【推荐】两大类。说明 对内容做了引申和解释;正例 给出正确的代码示例;反例 给出错误的代码示范; 命名规约 【强制】代码中的命名严禁使用拼音及英文混合的方式,更不允许直接出现中文的方式,最好也不要使用下划线或者美元符号开头; 1 反例:_name $name / 学生 / getPingfenByName()[评分] 【强制】文件名、class、struct、enum、protocol 命名统一使用 UpperCamelCase 风格; 1 2 正例:class LoginName { } / enum SexType { } 反例:class loginName { } / enum SexTYPE { } 【强制】方法名、参数名、成员变量、局部变量、枚举成员统一使用 lowerCamelCase 风格 1 2 正例:localValue / getMessageInfo() 反例:LocalValue / GetMessageInfo() 【强制】命名中出现缩略词时,缩略词要么全部大写,要么全部小写,以首字母大小写为准,通用缩略词包括 JSON、URL、ID 等; 1 2 正例:class IDUtil {} / func idToString() 反例:class IdUtils {} / func iDToString() 【强制】不要使用不规范的缩写,力求语义表达完整清楚,能直观的表达意图,不怕名称长; ...

November 16, 2024 · 5 min · 1041 words · CoderStar

同层渲染

前言 可能作为 iOS 开发者,对同层渲染这个名词比较陌生,但是如果大家开发过小程序,应该对这个名词就不会陌生,因为小程序中有一类组件叫做原生组件(native-component),比如 camera、video 等,这类组件在渲染过程中最终会映射成下文提到的原生组件。 在正文开始之前,先给大家统一几个概念,方便后续的阅读。 原生组件:iOS、Android 等客户端 Native 组件,如 iOS 中的 UITextField、UITextView,Android 中的 EditText、ListView 等; H5 组件:是指 HTML5 语言编写的 web 组件,如 <input/>、 <textarea></textarea> 等; 相比于 H5 组件,原生组件不仅可以提供 H5 组件无法实现的一些功能,还能提升用户体验上的流畅度(特别是对于音视频播放器而言),又因为减少了客户端代码与 WebView 通信的流程,降低了通信开销,简单来说,原生组件功能全、速度快、开销少; 应用及概念 任何技术的产生都是伴随着需求或问题,那么同层渲染的产生到底是解决什么问题呢? 我们上文已经提到原生组件比 H5 组件性能更好,所以说对于一些 H5 组件,我们希望其在客户端渲染时被映射成原生组件,那么问题来了:作为客户端来讲,我们一般会采用 WebView 加载 HTML,原生组件脱离在 WebView 渲染流程外,如果把 WebView 看成单独的一层,那么原生组件则位于另一个更高的层级。那么这样的层级就带来了一些问题: 原生组件的层级是最高的:页面中的其他组件无论设置 z-index 为多少,都无法盖在原生组件上; 部分 CSS 样式无法应用于原生组件; 原生组件无法在 scroll-view 等可滚动的 H5 组件中使用:因为如果开发者在可滚动的 DOM 区域,插入原生组件作为其子节点,由于原生组件是直接插入到 WebView 外部的层级,与 DOM 之间没有关联,所以不会跟随移动也不会被裁减。 未同层渲染的层级图如下图所示: <!DOCTYPE html> Responsive Image ...

November 16, 2024 · 3 min · 585 words · CoderStar