Pancake 0.5.0

Pancake 0.5.0

测试已测试
语言 SwiftSwift
许可证 MIT
发布上次发布2017年11月
SwiftSwift版本4.0
SPM支持SPM

Zach Radke维护。



Pancake 0.5.0

  • Zach Radke

Pancake

CI Status
Cocoapods Version
Carthage Compatible
Platform
License


http://khanlou.com/2017/10/the-flat-cache/启发的Swift实现的扁平缓存

特性

  • 使用Cache作为单一真相来源
  • 观察Cached值随时间的变化
  • 表示触发观察的Related
  • 根据需要剪枝未观察到的值

要求

  • Xcode 9.0+
  • Swift 4.0
  • iOS 8.0+

安装

CocoaPods

将以下行添加到您的Podfile

pod 'Pancake'

Carthage

将以下行添加到您的Cartfile

github "zradke/Pancake"

使用

创建一个Identifiable模型

要插入到Cache中,类型只需是Identifiable

struct Book: Identifiable {
    typealias ISBN = Int
    var identifier: ISBN
    var title: String
}

任何类型都可以作为Identifier使用,只要它符合CustomStringConvertibleHashableCodable。由于Cache更适合使用值类型而不是引用类型,因此对于模型和Identifier都应首选使用struct而不是class

Cache中添加值

任何Identifiable值都可以插入到Cache

let cache = Cache()
let book = Book(identifier: 9788700631625,
                title: "Harry Potter and the Sorcerer's Stone")
cache.set(book)

一旦在Cache中,就可以使用类型标识符来检索值

let retreivedBook: Book? = cache.get(9788700631625)

观察Cached

Cache中的值也可以包裹成Cached

let cachedBook: Cached<Book> = cache.cached(9788700631625)

Cached值从Cache提供最新的值,同时也可以被观察

// Retreives the latest value from the `Cache`
let currentValue = cachedBook.value

// Executes the closure whenever the value is changed in the `Cache`
let disposable = cachedBook.observe { (book) in
    // update user interface etc.
}

请注意,CachedValue.observe(_:)返回一个Cache.Disposable,必须保留以保持观察的生命周期。一旦它被释放,观察就会自动结束。

高级使用

Mergeable模型

API通常会返回相同模型的未完整表示。如果类型是Mergeable,则Cache可以逐渐建立完整的模型

struct Book: Identifiable, Mergeable {
    typealias ISBN = Int
    var identifier: ISBN
    var title: String?
    var publishedOn: Date?
    
    func merged(with other: Book) -> Book {
        var copy = self
        
        if let title = other.title { copy.title = title }
        if let publishedOn = other.publishedOn { copy.publishedOn = publishedOn }
        
        return copy
    }
}

当一个Mergeable值被插入到缓存中时,它会与任何现有值合并

let bookStub = Book(identifier: 9788700631625,
                    title: "Harry Potter and the Sorcerer's Stone",
                    publishedOn: nil)
cache.set(bookStub)

// Later from a different API...
let detailedBook = Book(identifier = 9788700631625,
                        title: nil,
                        publishedOn: "1998-09-01".toDate())
cache.set(detailedBook)

let compositeBook: Book = cache.get(9788700631625)!
compositeBook.title // "Harry Potter and the Sorcerer's Stone"
compositeBook.publishedOn // 1998-09-01

创建大量模型的Mergeable实现可能是苦差事,在这种情况下可以使用Sourcery

具有HasCachedRelationships的模型

模型通常具有关系。通过存储所有值的单一表示并允许通用关系,Cache可以帮助归一化数据。类型通过符合HasCachedRelationships来指示它具有关系,这通常由任何Related属性构建

struct Author: Identifiable, HasCachedRelationships {
   ...
   
   var books: Set<Related<Book>>
   
   var relatedCacheKeys: Set<CacheKey> {
       return books.map { $0.cacheKey }
   }
}

struct Book: Identifiable, HasCachedRelationships {
    ...
    
    var author: Related<Author>
    
    var relatedCacheKeys: Set<CacheKey> {
        return [author.cacheKey]
    }
}

Related值可以通过使用Related.cached(in:)来转换为Cached值以访问其实际值。然而,HasCachedRelationships的更大好处是,当缓存中相关对象变化时,观察者会被通知,这使得依赖于嵌套值的UI始终保持在同步状态

let cache = Cache()
var author = Author(identifier: 1,
                    name: "JK Rowling")
let book = Book(identifier: 9788700631625,
                title: "Harry Potter and the Sorcerer's Stone",
                author: Related(author))
author.books.append(Related(book))

cache.set(author)
cache.set(book)

let disposable = cache.cached(book).observe { (value) in
    // Update UI
}

author.bornOn = "1965-07-31".toDate()

cache.set(author) // Notifies the UI

Cache非常智能,能够处理循环关系和任意深度的关系(尽管太深可能会导致性能问题)。

类似于Mergeable,创建HasCachedRelationships.relatedCacheKeys通常涉及样板代码,所以我建议使用Sourcery来自动化大量模型的过程。

批处理更新

API通常会返回除主要模型外的相关模型,所有这些模型都在处理期间需要插入Cache。然而,作为对Cache的单独调用可能会产生性能影响,因为Cache需要做一些工作来确保线程安全,更不用说所有将被生成的观察结果。

因此,对Cache执行批处理操作是有用的。

cache.performBatchUpdates { (cache) in
    cache.set(...)
    cache.set(...)
}

在批量更新期间,闭包被赋予一个CacheType,这是Cache的一个精简版本,可以用来获取和设置缓存中的值。给定的CacheType在多个线程中使用是不安全的,但这也使它使用起来更快。观察结果在闭包之后合并并执行。

作者

Zach Radke,[email protected]

许可证

Pancake在MIT许可下可用。更多信息请参阅LICENSE文件。