Skip to content

Instantly share code, notes, and snippets.

@JohnEstropia
Last active September 27, 2017 05:06
Show Gist options
  • Save JohnEstropia/d0d3c59c715bb4e59b65e4ad3be5ea68 to your computer and use it in GitHub Desktop.
Save JohnEstropia/d0d3c59c715bb4e59b65e4ad3be5ea68 to your computer and use it in GitHub Desktop.
Collection that lazily initializes and caches its elements. Initially requires only the indexes and initializes elements as needed (e.g. UITableView data)
//
// LazyCachedCollection.swift
//
// Created by John Estropia on 2017/09/27.
// Copyright © 2017 John Estropia. All rights reserved.
//
import Foundation
class LazyCachedCollection<Element>: RandomAccessCollection {
init(_ indices: CountableRange<Index>, _ initializer: @escaping (Index) -> Element) {
self.startIndex = indices.lowerBound
self.endIndex = indices.upperBound
var cache: [(Index, Element)] = []
self.lazyEnumeration = indices.enumerated().lazy.map { (offset, index) -> (index: Index, element: Element) in
if offset < cache.endIndex {
return cache[offset]
}
let value = initializer(index)
let tuple: (index: Index, element: Element) = (index: index, element: value)
cache.append(tuple)
return tuple
}
}
// MARK: Sequence
typealias Iterator = AnyIterator<Element>
func makeIterator() -> Iterator {
var indexIterator = self.lazyEnumeration.makeIterator()
return AnyIterator { indexIterator.next()?.element }
}
// MARK: Collection
typealias Index = Int
let startIndex: Index
let endIndex: Index
subscript(position: Index) -> Iterator.Element {
return self.lazyEnumeration.first(where: { (index, _) in position == index })!.1
}
func index(after i: Index) -> Index {
return self.indices.index(after: i)
}
// MARK: Private
private let lazyEnumeration: LazyMapSequence<EnumeratedSequence<CountableRange<Index>>, (index: Index, element: Element)>
}
@JohnEstropia
Copy link
Author

Usage:

let collection = LazyCachedCollection<String>(0 ..< 6) { (index) -> String in
    print("cache added: \(index)")
    return "Item\(index)"
}
print("= \(collection[3]) // Initializes 4 items")
print("= \(collection[2]) // Uses cached values")
print("= \(collection[5]) // Initializes 2 more items")

Output

cache added: 0
cache added: 1
cache added: 2
cache added: 3
= Item3 // Initializes 4 items
= Item2 // Uses cached values
cache added: 4
cache added: 5
= Item5 // Initializes 2 more items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment