Vellum

codebeat badge build test SwiftPM Compatible Version License Platform

要求

安装

Cocoapods

Vellum 可通过 CocoaPods 获得。 要安装它,只需将以下行添加到您的 Podfile 中

pod 'Vellum'

通过 XCode 使用 Swift Package Manager

通过 Package.swift 使用 Swift Package Manager

Package.swift 中将它添加为您的 target 依赖项

dependencies: [
    .package(url: "https://github.com/hainayanda/Vellum.git", .upToNextMajor(from: "1.2.3"))
]

在你的 target 中使用 Vellum

 .target(
    name: "MyModule",
    dependencies: ["Vellum"]
)

然后在你使用它之前运行 swift build 来构建依赖项

作者

Nayanda Haberty, hainayanda@outlook.com

许可证

Vellum 在 MIT 许可下可用。 有关更多信息,请参见 LICENSE 文件。

存储算法

Vellum 使用 LRU 算法。 它包含两种类型的存储,即内存存储磁盘存储。 两种大小都可以手动分配。

存储数据

alt text

  1. 将数据存储到内存存储
  2. 如果内存存储已满,它将从内存中删除最早访问的数据,直到空间足够容纳新数据
  3. 数据存储在内存中
  4. 将数据存储到磁盘存储
  5. 如果磁盘存储已满,它将从内存中删除最早访问的数据,直到空间足够容纳新数据
  6. 数据存储到磁盘

获取数据

alt text

  1. 从内存存储中查找数据
  2. 如果数据存在,它将返回数据,步骤结束
  3. 如果数据在内存中不存在,它将尝试从磁盘存储中查找数据
  4. 如果数据存在,它会将数据存储到内存存储中以供将来更快使用,并返回数据,步骤结束
  5. 如果数据不存在,它将返回 nil

使用示例

基本用法

您需要做的就是从工厂获取 ArchiveManager 并存储您的对象,该对象实现了 ArchivableCodable,或者使用 typealias ArchiveCodable,它们是相同的

let archives = try! ArchivesFactory.shared.archives(
    for: MyArchivable.self,
    trySetMaxMemorySize: 10.megaByte, 
    trySetMaxDiskSize: 20.megaByte
)

// will insert object
archives.record(myObject)

let object = archives.access(archiveWithKey: "object_key")

Archivable

Archivable 实际上只是一个协议,它具有将对象转换为数据或反之亦然的方法。 Archivable 确保对象也具有键

class User: Archivable {
    
    var primaryKey: String { userName }
    var userName: String = ""
    var fullName: String = ""
    var age: Int = 0
    
    func archive() throws -> Data {
        // do something to convert the object to Data
    }
    
    static func deArchive(fromData data: Data) throws -> Archivable {
        // do something to convert the data to object
    }
}

ArchiveCodable

如果您的对象是 Codable,只需添加 Archivable 或使用 typealias ArchiveCodable,它们是相同的,您的对象将自动拥有这些方法。 您只需要添加您想要的 primaryKey 属性作为主键,只要该值是 String

struct User: Codable, Archivable {
    var primaryKey: String { userName }
    var userName: String
    var fullName: String
    var age: Int
}

ArchiveManager

要获取 ArchiveManager,您可以使用 ArchivesFactory。 您可以分配内存大小和磁盘大小的最大字节数。 但请记住,该大小仅适用于首次创建 ArchiveManager 时,如果已创建缓存管理器,则将忽略内存大小和磁盘大小。 如果您不分配内存大小或磁盘大小,它将使用默认值,内存为 1 兆字节,磁盘大小为 2 兆字节

let archives = try! ArchivesFactory.shared.archives(
    for: User.self, 
    trySetMaxMemorySize: 10.kiloByte, 
    trySetMaxDiskSize: 20.kiloByte
)

// or not explicit
let sameArchives: ArchiveManager<User> = try! ArchivesFactory.shared.archives( 
    trySetMaxMemorySize: 10.kiloByte, 
    trySetMaxDiskSize: 20.kiloByte
)

ArchiveManager 具有一些可用的方法和属性,如下所示:

Query

您可以从缓存中进行查询。 有 3 种类型的查询,分别是

所有查询都可以组合,并将按顺序执行

let results = userCache.findWhere { archive in
    archive.userName(.contains("premium"))
        .fullName(.isNotEqual(nil))
}
.getResults()

上面的代码将查找缓存中所有 userName 包含 "premium" 且 fullName 不为 nil 的用户。 结果是 User 的数组

let results = userCache.sorted { by in 
    by.age(.ascending)
        .fullName(.descending)
}
.getResults()

上面的代码将获取缓存中的所有用户,并按其年龄升序排序,然后按其 fullName 降序排序。 结果是排序后的 User 数组

您也可以添加 limit

let results = userCache.sorted { by in 
    by.age(.ascending)
        .fullName(.descending)
}
.limitResults(by: 10)
.getResults()

上面的代码将限制结果最多为 10 个

如果您愿意,甚至可以组合查询

let results = userCache.findWhere { archive in
    archive.userName(.contains("premium"))
        .fullName(.isNotEqual(nil))
}
.sorted { by in 
    by.age(.ascending)
        .fullName(.descending)
}
.limitResults(by: 10)
.getResults()

上面的代码将查找缓存中所有 userName 包含 "premium" 且 fullName 不为 nil 的用户,然后按其年龄升序排序,然后按其 fullName 降序排序。 结果限制为 10 个。

以下是可以与 QueryFinder 一起使用的 finder 列表

如果您想手动验证,您可以只使用 isValid(_ validator: (Property) -> Bool)

let results = userCache.findWhere { archive in
    archive.userName(.isValid { $0.contains("premium") })
}
.getResults()

Property Wrapper

您可以使用 Archived property wrapper 来包装任何属性,因此如果分配它,它将自动将这些属性存储到 ArchiveManager

@Archived var user: User?

如果您希望该属性基于给定的主键具有初始值,只需传递该键

@Archived(initialPrimaryKey: "some") var user: User?

上面的代码将尝试在第一次属性加载时获取具有给定键的用户。