Swift - 使用 Protocol 避免框架之间循环引用
将高度复用的代码封装到静态库中不仅可以将代码解耦,还可以提高代码的可维护性。笔者所在公司的iOS项目是使用模块化开发的,项目中大量的可复用代码都被封装成静态库。
静态库的循环引用
设想这样的一个场景
A Framework 引用 B Framework,而此时B Framework 需要使用到 A Framework 中的一个服务。但不幸的是该服务耦合 在A Framework 中,为了避免引用循环,我们需要重构 A Framework,并且将该服务迁移到另外一个 C Framework 中。
我相信在现实中,没有程序员原意冒着风险去重构 A Framework 的代码和单元测试(有这个时间,老子还不如去多玩几把玩者)。
使用Protocol 解决循环引用
在这里笔者提供一种思路来帮助大家在无需重构现有代码的前提下,将 A Framework 中的服务暴露给 B Framework。
这里的示例代码可以在文末的 Github 链接中下载到
准备工作
在我们主项目中,我们定义了一个 Color
服务
protocol ColorLayer {func backgroundColor() -> UIColor
}class ColorService: ColorLayer {func backgroundColor() -> UIColor {return .red}
}
复制代码
这时候我们新建一个静态库,并命名为 BridgeTestFramework
在这个静态库中,我们有这样的一段代码。
public class BridgeViewController: UIViewController {let colorService = ColorService()public override func viewDidLoad() {super.viewDidLoad()view.backgroundColor = colorService.backgroundColor()}
}
复制代码
由于 BridgeTestFramework
被主项目引用,而 BridgeTestFramework
不能引用主项目,故编译器会给出错误。
在 BridgeTestFramework
中定义 Protocol
复制 ColorService
的 Protocol 到 BridgeTestFramework
中,别忘记小改一下这个 Protocol 的名字并将其访问权限更改为 public
。
public protocol BridgeTestFrameworkColorLayer {func backgroundColor() -> UIColor
}
复制代码
接着我们重构一下 BridgeViewController
public class BridgeViewController: UIViewController {let colorService: BridgeTestFrameworkColorLayerpublic init(colorService: BridgeTestFrameworkColorLayer) {self.colorService = colorServicesuper.init(nibName: nil, bundle: nil)}required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}public override func viewDidLoad() {super.viewDidLoad()view.backgroundColor = colorService.backgroundColor()}
}
复制代码
在这里我们将属性 colorService
的类型用 BridgeTestFrameworkColorLayer
代替。由于 BridgeTestFrameworkColorLayer
和 ColorService
所暴露出来的 interface 是一样的,所以我们可以正常使用 backgroundColor()
这个方法。
在主项目中实现 Protocol
接着我们回到主项目的代码。为 ColorService
引入 BridgeTestFramework
,并拓展 ColorService
。
import BridgeTestFrameworkprotocol ColorLayer {func backgroundColor() -> UIColor
}class ColorService: ColorLayer, BridgeTestFrameworkColorLayer {func backgroundColor() -> UIColor {return .red}
}
复制代码
由于 ColorLayer
与 BridgeTestFrameworkColorLayer
所定义的 interface 是一样的,所以我们无需更改 ColorService
的具体实现。
使用 Protocol
接着我们尝试在主项目中使用一下我们重构后的 BridgeViewController
吧。
class ViewController: UIViewController {override func viewDidAppear(_ animated: Bool) {super.viewDidAppear(animated)let bridgeVC = BridgeViewController(colorService: ColorService())present(bridgeVC, animated: true, completion: nil)}
}
复制代码
由于 ColorService
实现了 BridgeTestFrameworkColorLayer
这个协议,BridgeViewController
可以正常使用 ColorService
对 backgroundColor()
这个 interface 的实现。
小结
在这个小 Demo 中我们使用 Protocol 在两个静态库之间搭起一座临时的桥梁。借助 Protocol 我们可以在避免循环引用的前提下,在已经存在从属引用关系的静态库之间分享某些服务。
但是请牢记,好的设计模式才是避免出现这种循环引用的根本解决方案。 Demo 源代码可以在这里下载到。
转载于:https://juejin.im/post/5cb973c36fb9a0689232252d
Swift - 使用 Protocol 避免框架之间循环引用相关推荐
- 深入学习c++--智能指针(二) weak_ptr(打破shared_ptr循环引用)
1. 几种智能指针 1. auto_ptr: c++11中推荐不使用他(放弃) 2. shared_ptr: 拥有共享对象所有权语义的智能指针 3. unique_ptr: 拥有独有对象所有权语义的智 ...
- OC和Swift中循环引用的问题
总结一下自己对OC中和Swift中循环引用的认识. 一.OC中的循环引用分为类中的循环引用和对象之间的循环引用. 1.类的循环引用 造成原因: 在两个类的.h文件中使用了#import "& ...
- 防止NSTimer和调用对象之间的循环引用
防止NSTimer和调用对象之间的循环引用 @interface NSTimer (EOCBlocksSupport)+ (NSTimer *)eoc_scheduledTimerWithTimeIn ...
- 解决Swift中callback循环引用 - Delegated(Library)
文章目录 前言 使用示例 一般闭包示例 Delegated 示例 源码解析 示例Demo 示例Demo地址 前言 在Swift中我们使用闭包(Callback)的时候经常要写 [weak self] ...
- Swift之常见闭包与defer关键字的使用分析和闭包中的循环引用 | CSDN创作打卡
一.什么是闭包? 在 Swift 中,可以通过 func 定义一个函数,也可以通过闭包表达式定义一个函数,闭包是一个捕获了上下文的常量或者是变量的函数.闭包(Closures)是自包含的功能代码块,可 ...
- iOS 循环引用 委托 (实例说明)
如何避免循环引用造成的内存泄漏呢: 以delegate模式为例(viewcontroller和view之间就是代理模式,viewcontroller有view的使用权,viewcontroller同时 ...
- 浅析 SpringMVC 中返回对象的循环引用问题
问题发现 今天这个话题还是比较轻松的,可能很多朋友也都遇到过这个问题. @RestController.@ResponseBody 等注解是我们在写 Web 应用时打交道最多的注解了,我们经常有这样的 ...
- 从循环引用谈依赖倒置原则
在业务开发中,通常会按照业务或者逻辑将项目分成好几个工程文件以方便重用和模块化,有时候我们分开的两个项目可能存在相互引用的情况,举个例子,比如有两个系统,订单系统和产品系统,订单系统需要从产品系统中了 ...
- 和block循环引用说再见
to be block? or to be delegate? 这是一个钻石恒久远的问题.个人在编码中暂时没有发现两者不能通用的地方,习惯上更偏向于block,没有什么很深刻的原因,只是认为block ...
最新文章
- 【Qt】Qt信号与槽使用不当,使程序崩溃
- hexo定制个人博客matery主体打开公式渲染
- tensorflow 中报错ValueError: Found input variables with inconsistent numbers of samples: [5492, 14280]
- 使用 Spot 低成本运行 Job 任务
- MySQL使用用户变量优化先更新后查询
- 三圆相交阴影部分面积_小学六年级图形面积的题很多家长都不会,一些初中生也未必会做...
- 《Unit Testing》1.4. 成功的测试套件拥有哪些属性?
- Servlet中防止盗链的代码
- java设计模式 组合_JAVA 设计模式 组合模式
- 提高篇 第五部分 动态规划 第2章 树型动态规划
- 自定义文件系统类加载器
- Eclipse安装反编译工具Eclipse Class Decompiler:实现不下载源码,查看源文件
- 网页打开慢/正在解析主机-解决
- 《.NET大局观》--嬗变的痛苦
- 详解 git cherry-pick用法
- python自然语言_Python自然语言处理 - 随笔分类 - 牛皮糖NewPtone - 博客园
- 计算机内存管理之虚拟内存
- 背负着24-70之名 佳能新老镜皇横向对比(MTF对比说明)
- 百度AI图像处理—人体分析(人像切割—AI抠图)调用教程(基于Python3-附Demo)
- VScode中无法使用转到定义
热门文章
- php 自学 经验,学习PHP:PHP学习的几个问题经验总结
- 电脑有电流声怎么解决_微星笔记本有电流声或者风扇声怎么办?
- php框架升级,【PHP开发框架】thinkphp怎么升级
- php 整形 字符串排序,php-通过特定的字符串值进行排序
- android中各属性布局,Android里面各布局的属性定义
- html与java接口_html用ajax请求服务器后端java接口跨域问题解决
- 第十六届全国大学生智能车竞赛百度智慧交通竞赛成绩
- 关于第十五届全国大学生智能车竞赛 STC 单片机
- linux挂载设备类型lvm,linux——管理系统设备之LVM的管理
- sgn matlab,matlab中.*的问题