我正在为我的网络模块进行缓存。我的模块将为每个请求向调用者返回一个AnyCancallable
。如果缓存的数据不可用,我使用URLSession.dataTaskPublisher
,它可以处理两个事件:数据接收和完成。如果缓存的数据可用,我将使用CurrentValueSubject
创建要返回的AnyCancallable。我发送了关于这个主题的两个事件,但在调用方,它只在完成时得到通知,没有数据。
cacheSubject.send(cachedData.data)
cacheSubject.send(completion: Subscribers.Completion<Error>.finished)
删除完成发送,现在它可以接收数据,但没有完成通知。
有人能告诉我我在这里做错了什么吗?
这是完整的文件,以防你们需要:
public class SSNetworkManager {
public static let shared = SSNetworkManager()
private var cache: [String: CachedData] = [:]
private let cacheSubject = CurrentValueSubject<Data, Error>(Data())
@discardableResult public func makeServiceCall<D: Decodable>(forRequest request: SSNetworkRequest<D>, onMainThread: Bool = true) -> AnyPublisher<D, Error>? {
guard let urlRequest = request.urlRequest else {
return nil
}
var cancelable: AnyPublisher<Data, Error>
if let url = urlRequest.url?.absoluteString,
let cachedData = cache[url],
cachedData.isValid {
cancelable = cacheSubject.eraseToAnyPublisher()
cacheSubject.send(cachedData.data)
cacheSubject.send(completion: Subscribers.Completion<Error>.finished)
} else {
cancelable = URLSession.shared.dataTaskPublisher(for: urlRequest).tryMap {[weak self] (data, response) -> Data in
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw SSNetworkError(httpCode: (response as? HTTPURLResponse)?.statusCode ?? 0, data: data)
}
if request.shouldCacheNow,
let url = urlRequest.url?.absoluteString {
self?.cache[url] = CachedData(data: data, expirationTime: request.cacheExpirationTime)
}
return data
}.eraseToAnyPublisher()
}
if onMainThread {
return cancelable
.receive(on: RunLoop.main)
.decode(type: D.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
} else {
return cancelable
.decode(type: D.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
}
}
fileprivate struct CachedData {
let data: Data
let expirationTime: Date
var isValid: Bool {
return Date().compare(expirationTime) != .orderedDescending
}
}
这不是使用主题的正确情况。相反,返回与每个案例相关的发布者:
public class SSNetworkManager {
// ...
public func makeServiceCall<D: Decodable>(
forRequest request: SSNetworkRequest<D>,
onMainThread: Bool = true
) -> AnyPublisher<D, Error>? {
// consider just returning Empty().eraseToAnyPublisher() instead of nil
guard let urlRequest = request.urlRequest else {
return nil
}
var resultPublisher: AnyPublisher<D: Error>
if let url = urlRequest.url?.absoluteString,
let cachedData = cache[url],
cachedData.isValid {
resultPublisher = Just(cachedData.data)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
} else {
resultPublisher = URLSession.shared
.dataTaskPublisher(for: urlRequest)
.tryMap { ... }
.decode(type: D.self, decoder: JSONDecoder())
.eraseToAnyPublisher()
}
return onMainThread
? resultPublisher
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
: resultPublisher
.eraseToAnyPublisher()
}
}