Swift Combine:发送值后发送完成

Swift Combine: send completion after send value

我正在为我的网络模块进行缓存。我的模块将 return 一个 AnyCancallable 返回给每个请求的调用者。如果缓存数据不可用,我使用 URLSession.dataTaskPublisher,它适用于 2 个事件:数据接收和完成。如果缓存数据可用,我将使用 CurrentValueSubject 创建 AnyCancallable 到 return。我发送了关于这个主题的两个事件,但在调用方,它只在完成时收到通知,没有数据。

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
    }
}

这不适合使用主题。相反,return 发布者,与每个案例相关:

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()
    }
}