# 前语
本文便是 上篇 文章结尾所说到的替换 RxSwift
。
本文篇幅也会太长,触及内容也仅仅是 Combine
的运用,您完全能够将此 demo
当下手 Combine
的上手试验。文末会附上 Combine
学习的网址,相同有文中源码附上。
老传统了,看图吧
# 网络层替换
增加对应的 Moya/Combine
后,对网络层选用 网络弥补 中的封装方法,相同供给 request()
, memoryCacheIn(_)
,onStorage(_:atKeyPath:onDisk:)
办法。现将缓存相关的 extension
抽离到 Moya+XTCache.swift
中,封装如下:
extension TargetType {
public func request() -> AnyPublisher<Response, MoyaError> {
xtProvider.requestPublisher(.target(self))
}
/// 运用时间缓存策略, 内存中有数据就不恳求网络
public func memoryCacheIn(_ seconds: TimeInterval = 180) -> TargetOnMemoryCache {
TargetOnMemoryCache(target: self, cacheTime: seconds)
}
/// 读取磁盘缓存, 一般用于启动时先加载数据, 而后真正的读取网络数据
public func onStorage<T: Codable>(_ type: T.Type, atKeyPath keyPath: String? = nil, onDisk: ((T) -> ())?) -> TargetOnDiskStorage<T> {
let diskStore: TargetOnDiskStorage<T> = .init(target: self, keyPath: keyPath)
if let storage = diskStore.readDiskStorage(type) { onDisk?(storage) }
return diskStore
}
}
关于 memoryCache
的处理没有选用,extension AnyPublisher {}
的方法,如下:
extension AnyPublisher {
func request() -> AnyPublisher<Response, MoyaError> where Output == (TargetType, TimeInterval), Failure == MoyaError {
flatMap { tuple -> AnyPublisher<Response, MoyaError> in
let target = tuple.0
let cacheKey = target.cacheKey
if let response = cachedResponse(for: cacheKey) {
return CurrentValueSubject(response).eraseToAnyPublisher()
}
return target.request().map { response -> Response in
kMemoryStroage.setObject(response, forKey: cacheKey, expiry: .seconds(seconds))
return response
}
.eraseToAnyPublisher()
}
.eraseToAnyPublisher()
}
}
运用 CurrentValueSubject
确保在被订阅时是有值的,具体的 RxSwift
与 Combine
对照表见文末 弥补 部分。
# ViewModel 替换
Combine
的 Publiser
指定了 Failure
,因而关于咱们在 RxSwift
中不会发送 error
的 Observable
来说,能够明晰的定义为 AnyPublisher<SendType, Never>
类型,如:
// RxSwift
var moreData: Observable<DynamicDisplayModel> { get }
// Combine
var moreData: AnyPublisher<DynamicDisplayModel, Never> { get }
用 Combine
的 PassthroughSubject<SendType, Never>
替换 RxSwift
的 PublishSubject<SendType>
。
这儿要注意的一点便是 Combine
的 flatMap
操作符并不如 RxSwift
中那么好用,如下图展示过错所示:
AnyPublisher<XTListResultModel, MoyaError>
在 iOS 13
版别不支持转换为 AnyPublisher<Result<XTListResultModel, Error>, Never>
,iOS 14
之后才干运用,这一部分咱们运用 map
替换,如下图:
# 弥补
1. Combine 学习网址:
-
Combine 入门导读
-
Rxswift与Combine对照表
-
Using Combine-中文
主张次序阅览
2. Combine 弥补
receive(on: main)
和 subscribe(on: main)
的区别。receive(on: main)
确保 .sink {}
中的代码是在 main thread
中履行。 具体可参阅文章 subscribe-revcive
3. 自定义 Publisher
在 demo 的 TextureDemoViewController.swift
中有一个自定义的 JsonDataPublisher
。相同在 Moya/Combine
和 Nuke/Combine
中也有自定义的 Publisher
可供学习。
4. 移除 Kingfisher,SnapKit
demo 的 MOON
分支移除了 SnapKit
理由是用的而当地太少,运用手写束缚布局替换
// SnapKit
button.snp.makeConstraints { make in
make.left.equalToSuperview()
make.top.equalToSuperview()
make.bottom.equalToSuperview()
make.width.equalToSuperview().dividedBy(CGFloat(count))
}
// AutoLayout
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.leftAnchor.constraint(equalTo: previousButton?.rightAnchor ?? self.leftAnchor),
button.topAnchor.constraint(equalTo: self.topAnchor),
button.bottomAnchor.constraint(equalTo: self.bottomAnchor),
button.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 1/CGFloat(count))
])
运用 Nuke
替换 Kingfisher
纯个人兴趣。更多 Nuke
阐明,参照 Nuke-Doc 与 Nuke-demo。
感谢您的阅览。