如何在远程使用swift联合收割机之前正确地从缓存中提取

如何在远程使用swift联合收割机之前正确地从缓存中提取,swift,combine,Swift,Combine,为了填充字段,我执行许多重复请求。我希望缓存结果并在下次使用缓存的值 public func getItem(_ id: String) -> AnyPublisher<Item?, Never> { if let item = itemCache[id] { return Just(item).eraseToAnyPublisher() } return downloadItem(id: id) .map { item

为了填充字段,我执行许多重复请求。我希望缓存结果并在下次使用缓存的值

public func getItem(_ id: String) -> AnyPublisher<Item?, Never> {
    if let item = itemCache[id] {
        return Just(item).eraseToAnyPublisher()
    }

    return downloadItem(id: id)
        .map { item in
            if let item = item {
                itemCache[id] = item
            }
            return item
        }
        .eraseToAnyPublisher()
    }
}

func downloadItem(_ id: String) -> AnyPublisher<Item?, Never> { ... }

但是,所有请求都在调用
downloadItem
downloadItem
在主队列中返回。我还尝试将整个
getItem
函数包装到Deferred中,但结果相同。

首先,问题是函数正在求值,只返回发布者。因此,在每次订阅网络发布服务器之前,都会对缓存检查进行评估。使用
延迟
是正确的解决方法。然而,这仍然没有解决问题

相反,解决方案是在网络请求挂起时首先缓存共享发布服务器,这样网络调用期间的所有请求都将使用同一发布服务器,然后在完成后缓存
发布服务器以供将来所有调用:

public func getItem(_ id: String) -> AnyPublisher<Item?, Never> {
    if let publisher = self.publisherCache[id] {
        return publisher
    }

    let publisher = downloadItem(id)
        .handleEvents(receiveOutput: {
            // Re-cache a Just publisher once the network request finishes
            self.publisherCache[id] = Just($0).eraseToAnyPublisher()
        })
        .share() // Ensure the same publisher is returned from the cache
        .eraseToAnyPublisher()

    // Cache the publisher to be used while downloading is in progress
    self.publisherCache[id] = publisher

    return publisher
}
public func getItem(\uid:String)->AnyPublisher{
如果让publisher=self.publisherCache[id]{
返回发布者
}
让发布者=下载项(id)
.手柄通风口(接收输出:{
//网络请求完成后重新缓存Just publisher
self.publisherCache[id]=Just($0).eraseToAnyPublisher()
})
.share()//确保从缓存返回相同的发布服务器
.删除任何发布者()
//缓存下载过程中要使用的发布服务器
self.publisherCache[id]=发布者
返回发布者
}
需要注意的是,
downloadItem(id)
是异步的,在主循环中接收。当我用
Just(Item())
替换
downloadItem(id)
进行测试时,这不起作用,因为整个发布链都是在创建时评估的。使用
Just(Item()).recieve(on:Runloop.main)
在测试时修复该问题

public func getItem(_ id: String) -> AnyPublisher<Item?, Never> {
    if let publisher = self.publisherCache[id] {
        return publisher
    }

    let publisher = downloadItem(id)
        .handleEvents(receiveOutput: {
            // Re-cache a Just publisher once the network request finishes
            self.publisherCache[id] = Just($0).eraseToAnyPublisher()
        })
        .share() // Ensure the same publisher is returned from the cache
        .eraseToAnyPublisher()

    // Cache the publisher to be used while downloading is in progress
    self.publisherCache[id] = publisher

    return publisher
}