如何在 Swift 中实现多继承?
怎么做到自动检查
Controller
被销毁?Swift
中的KVO
可以不基于Runtime
吗?如何优雅的实现
TableView
刷新动效?不需管理
key
是否还可以使用UserDefaults
?
1. 如何在 Swift 中实现多继承?
1.1 实现过程
Swift 本身并不支持多继承,但我们可以根据已有的 API 去实现。
Swift 中的类可以遵守多个协议,但是只可以继承一个类,而值类型(结构体和枚举)只能遵守单个或多个协议,不能做继承操作。
多继承的实现:协议的方法可以在该协议的extension
中实现
无论是结构体还是类还是枚举都可以遵守多个协议,所以多继承就这么做到了。
1.2 通过多继承为 UIView
扩展方法
2. 怎么做到自动检查 Controller 被销毁?
检查内存泄漏除了使用 Instruments
,还有查看控制器 pop
或 dismiss
后是否被销毁,后者相对来说更方便一点。但老是盯着析构函数 deinit
看日志输出是否有点麻烦呢?
UIViewController
有提供两个不知名的属性:
isBeingDismissed
: 当modal出来的控制器被dismiss
后的值为true
。isMovingFromParent
: 在控制器的堆栈中,如果当前控制器从父控制器中移除,值会变成true
。
如果这两个属性都为 true
,表明控制器马上要被销毁了,但这是由 ARC 去做内存管理,我们并不知道多久之后被销毁,简单起见就设个 2 秒吧。
我们把这个方法添加到 viewDidDisappear(_:)
中
如果发生循环引用,控制就不会被销毁,会触发 assert
报错。
3. Swift中的 KVO 可以不基于 Runtime 吗?
Swift 并没有在语言层级上支持 KVO,如果要使用必须导入 Foundation
框架,被观察对象必须继承自 NSObject
,这种实现方式显然不够优雅。
KVO 本质上还是通过拿到属性的 set 方法去搞事情,基于这样的原理我们可以自己去实现。
3.1 实现
话不多说,直接贴代码,新建一个 Observable
文件
使用起来和 KVO 差不多。
3.2 使用
需要监听的类
public class User {
// 监听的属性需要是 Observable 类型
public let name: Observable<String>
public init(name: String) {
self.name = Observable(name)
}
}
使用
// 创建对象
let user = User(name: "Made")
// 设置监听
user.name.addObserver(self, options: [.new]) { name, change in
print("name:\(name), change:\(change)")
}
// 修改对象的属性
user.name.value = "Amel"
// 这时就可以被监听到
// 移除监听
user.name.removeObserver(self)
注意: 在使用过程中,如果改变 value,addObserver方法不调用,很有可能是 Observer 对象已经被释放掉了。
4. 如何优雅的实现 TableView 刷新动效?
1. 简单的实现
我们都知道TableView
的刷新动效是设置在tableView(_:,willDisplay:,forRowAt:)
这个方法中的。
这样一个简单的淡入效果就 OK 了,但这样做显然不够优雅,我们如果要在多个TableView
使用这个效果该怎样封装呢?
2. 使用工厂设计模式进行封装
2.1 creator(创建者): Animator
,用来传入参数,和设置动画![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/cd161e740d5a781ae19fdc847c6e8ff6.jpeg)
2.2 product(产品): AnimationFactory
,用来设置不同的动画类型
将所有的动画设置封装在 Animation 的闭包中。
最后我们就可以在tableView(_:,willDisplay:,forRowAt:)
这个方法中使用如下代码,就实现最终效果
5. 不需管理 key是否还可以使用 UserDefaults ?
用来做简单数据存储的 Preference
在我们的日常开发中使用的还是比较多的,但使用起来总感觉不那么方便。比如说需要去手动管理 key
,之前是这样做的。
我们可以通过使用 #function
避免手动管理 key
,在存储和读取数据时调动的 set
和 get
方法也可以交给目标属性默认的 set
和 get
方法去做,。
在测试环节经常需要在测试服和正式服来回切换,为了避免老是打包,我们可以利用 UserDefaults
去更改服务器地址,在适当的位置(可以是个测试页面)加个 UISwitch
,然后设置 serverUrl
的值。
UserDefaults
有性能问题吗?UserDefaults
是带缓存的。它会把访问到的key
缓存到内存中,下次再访问时,如果内存中命中就直接访问,如果未命中再从文件中载入。它还会时不时调用同步方法来保证内存与文件中的数据的一致性,有时在写入一个值后也最好调用下这个方法来保证数据真正写入文件。
更多
限于篇幅原因这里分享部分Tips,更多内容如 使用面向协议实现 app 的主题功能,线程安全: 互斥锁和自旋锁,给UIViewController添加静态Cell 等点击 阅读原文 查看,本篇来自读者 Dariel 投稿,这里也欢迎更多的读者朋友推荐分享。
推荐阅读:
https://github.com/DarielChen/SwiftTips