Как правильно вытащить из кеша перед удаленным использованием swift объединить - PullRequest
1 голос
/ 02 апреля 2020

Я выполняю много повторных запросов, чтобы заполнить поле. Я хотел бы кэшировать результат и использовать кэшированное значение в следующий раз.

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

И это называется так:

Just(["a", "a", "a"]).map(getItem)

Однако все запросы вызывают downloadItem. downloadItem возвращается в основную очередь. Я также попытался обернуть всю функцию getItem в Deferred, но это дало тот же результат.

1 Ответ

0 голосов
/ 03 апреля 2020

Во-первых, проблема заключалась в том, что функция оценивается и возвращается только издатель. Таким образом, проверка кэша выполняется каждый раз до того, как сетевой издатель будет подписан. Использование Deferred - правильное решение для этого. Однако это все еще не решило проблему.

Вместо этого было решено сначала кэшировать общего издателя, пока сетевой запрос находится в состоянии ожидания, поэтому все запросы во время сетевого вызова будут использовать одного и того же издателя, а затем, когда он будет завершен. для кэширования Just издателя для всех будущих вызовов:

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
}

Одно замечание: downloadItem(id) является асин c и принимается на главном l oop. Когда я заменил downloadItem(id) на Just(Item()) для тестирования, это не сработало, потому что вся цепочка издателя была оценена при создании. Используйте Just(Item()).recieve(on: Runloop.main), чтобы исправить это во время тестирования.

...