Coherence,专为托管和前进时代设计的可配置CoreData扩展。Coherence帮助您构建需要持久性、离线存储、存储和转发以及Web连接的应用程序。它提供了一个全面的框架,以智能化和高效管理低级资源。
概述
连接
Coherence 的核心是资源管理服务,这些服务通过 Connect
协议进行暴露。Coherence 提供了一个基于 GenericConnect
类的通用具体实现 Connect
协议。Coherence 承担了持久容器的角色(实现 PersistentStack
协议),为您创建和管理核心数据栈。它提供的所有服务都是建立在 GenericConnect
实例之上的。
容器
Connect 的容器建立在 Coherence 容器之上,这是一个实现 PersistentStack
协议的组件。Connect 创建了一个实例
上下文策略
在一般使用中,可以根据您的用例配置几个不同的 CoreData 栈。为了方便这一点,Coherence 为您提供了 PersistentStack 实例使用的策略选择。《ContextStrategy》类封装了 CoreData 栈的 ManagedObjectContext 布局和行为。《Connect》目前内置了 4 种策略 Direct
、DirectIndependent
、IndirectNested
和 Mixed
。如果您需要自己的应用程序,也可以根据 ContextStrategyType
协议创建自己的策略。
直接模式
《ContextStrategy.Direct》管理与NSPersistentStoreCoordinator
直接连接的viewContext和BackgroundContext。对BackgroundContext
所做的更改将直接传播到持久存储,允许设置并尊重合并策略。
- 注意:当后台上下文保存时,视图上下文将保持最新状态并持久化到存储中。
直接独立
ContextStrategy.Independent
管理直接与NSPersistentStoreCoordinator
连接的独立上下文(视图和背景)。
- 注意:使用此策略时,视图上下文不会被更新以保持最新状态。
间接嵌套
ContextStrategy.Nested
管理通过根上下文间接连接到NSPersistentStoreCoordinator
的嵌套(父/子)上下文(视图中和后台)。
通过根上下文在后台间接执行对持久存储的更改传播。
- 注意:当后台上下文保存时,视图上下文将保持最新状态并持久化到存储中。
混合
ContextStrategy.Mixed
管理通过根上下文间接连接到NSPersistentStoreCoordinator
的嵌套(父/子)视图上下文以及直接连接到NSPersistentStoreCoordinator
的背景上下文。
对BackgroundContext所做的更改将直接传播到持久存储,允许设置并尊重合并策略。《viewContext》更新完全在内存中执行,并通过根Context在后台线程中间接传播到持久存储。
- 注意:当后台上下文保存时,视图上下文将保持最新状态并持久化到存储中。
用法
初始化 & 启动
在Coherence的初始化和启动过程中,你可以依赖其默认行为,或者完全掌控这些方面。
GenericConnect
和 GenericPersistentContainer
都实现了 PersistentStack
协议。这意味着初始化和启动序列相同,只是 GenericConnect
另外有一个要求,即必须 启动
实例。除此之外,它们作为 PersistentStack
完全可互换。
持久存储可以根据各种需求和使用案例分步附加和断开。例如,你可能想将一个全局存储启动,以便存储你的用户表,从而确定已登录的用户。用户信息可用于决定为该用户附加适当的存储。这可以通过 attachPersistentStore(for:)
和 detach(persistentStore:)
方法实现。
注意:
attachPersistentStore(for:)
和detach(persistentStore:)
都有复数形式(attachPersistentStores(for:)
和detach(persistentStores:)
),允许你一次性附加和断开多个存储。在attach
的情况下,你可以在同一位置(url
)附加多个存储。如果需要,这两种版本可以混合使用。
创建 Connect
或 PersistentStack
实例后,可以在任何时候附加存储。所有“附加”方法都接受一个 StoreConfiguration
,用于指定存储的各种方面以及一个指定文件位置的 url
。
以下我们为各种用例,包括前面提到的用例,创建了一些启动示例。
无配置要求
在这种情况下,开发者想要的是一个无烦恼、简单的配置,因此只需要Coherence的默认值。这个场景就像实例化后启动实例一样简单。
let connect: Connect = GenericConnect<ContextStrategy.Mixed>(name: "MyModelName")
try connect.start()
需要自定义配置
在这种情况下,开发者对他的持久存储有一个自定义的配置设置,希望保持这个设置。
let connect: Connect = GenericConnect<ContextStrategy.Mixed>(name: "MyModelName")
try connect.attachPersistentStores(for: [StoreConfiguration(name: "TransientData", type: NSInMemoryStoreType),
StoreConfiguration(name: "PersistentData", type: NSSQLiteStoreType)])
try connect.start()
在用户模型 TransientData
和 PersistentData
中定义了两种配置,它们将被存储在不同的持久存储中。对于 TransientData
,由于不需要在不同的应用程序启动间持续存储,它将存储在 NSInMemoryStoreType
中。PersistentData
另一方面,将持久存储在 NSSQLiteStoreType
存储中,位置在 defaultStoreLocation
。
每个用户配置
在此场景中,开发者希望在登录应用程序的用户中,每个用户都有一个配置/持久存储。
let connect: Connect = GenericConnect<ContextStrategy.Mixed>(name: "MyModelName")
let userName = loggedInUserName() /* Determine user that is logged */
try connect.attachPersistentStores(at: URL(fileURLWithPath: "/persistentStores/location/\(userName)"),
for: [StoreConfiguration(name: "TransientData", type: NSInMemoryStoreType),
StoreConfiguration(name: "PersistentData", type: NSSQLiteStoreType)])
try connect.start()
第一步是确定哪个用户已登录。一旦获得这些信息,就可以使用指向登录用户存储位置的 `url`,调用 attachPersistentStores(at:for:)
。
全局存储,每个用户配置
在此场景中,开发者在为应用程序登录的用户连接自定义配置/存储配置之前,首先启动全局持久存储。
let connect: Connect = GenericConnect<ContextStrategy.Mixed>(name: "MyModelName")
try connect.attachPersistentStore(at: URL(fileURLWithPath: "/persistentStores/location"), for: StoreConfiguration(name: "GlobalData", type: NSSQLiteStoreType))
let userName = loggedInUserName() /* Determine user that is logged */
try connect.attachPersistentStores(at: URL(fileURLWithPath: "/persistentStores/location/\(userName)"),
for: [StoreConfiguration(name: "TransientData", type: NSInMemoryStoreType),
StoreConfiguration(name: "PersistentData", type: NSSQLiteStoreType)])
try connect.start()
这可以通过首先打开持久用户数据库来定位登录用户的详细信息。确定之后,可以打开用户特定目录中的持久存储。此场景与上述场景非常相似,不同之处在于除了指定用户特定存储的 `url` 外,还指定了全局存储的 `url`。
初始化和开始的位置
可以将 Connect
实例存储在您的 AppDelegate
中,并将其注入到应用程序中,以访问 Coherence 提供的服务。在下面的代码块中,我们正是这样做的,并且还在 application(_:didFinishLaunchingWithOptions:)
中启动了实例。这是一个启动实例的常见位置,但它可以在任何您想使用的地方启动。
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let connect: Connect = GenericConnect<ContextStrategy.Mixed>(name: "ModelName")
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
do {
try self.connect.start()
} catch {
fatalError("\(error)")
}
return true
}
}
Coherence 不会对初始化或启动其实例位置施加任何限制,但了解,直到 Connect
实例启动,数据库操作和其他 Connect
提供的服务都不可用(包括您的 CoreData 栈)。
操作
Coherenc.Connect 包含一个基于其 Action
概念的广泛 进程管理和监控系统。动作封装了与远程系统通过网络服务保持数据缓存同步的相关工作,以及为在系统内运行通用任务提供一个环境。
动作的好处
- 在可管理的类中封装工作。
- 在受管理的容器中执行。
- 由容器提供受管理的服务。
- 可取消。
- 在执行过程中可监控。
- 在执行过程中捕获运行时统计信息。
- 可以由 Coherence 自动执行,以保持缓存同步(未来)
Connect 通过 execute()
函数执行动作,并返回一个 ActionProxy
,允许您控制并监控动作的执行。
动作主要有两种类型,分别是 GenericAction
和 EntityAction
,下面将详细介绍。
通用动作
通用动作
是一种能够封装、监控和控制几乎任何类型工作生命周期的动作,包括不与数据库交互的网络服务。下面的模板展示了一个构建您自己的动作的简单模板。该 Action
应实现 GenericAction
协议,并需要实现 2 个方法,即 execute()
和 cancel()
。这些方法在容器中将回调执行。
class MyGenericAction: GenericAction {
internal var canceled: Bool = false
///
/// This will be executed by the container
///
func execute() throws {
guard !canceled else { return }
/// Perform work here
}
func cancel() {
self.canceled = true
}
}
实体动作
此外,还有 EntityAction
,它封装了数据缓存同步功能,并提供特定数据库服务,同时提供与 GenericAction
相同的生命周期管理功能。
class MyEntityAction: EntityAction {
internal var canceled: Bool = false
private let webService: MyWebService
private let parameter1: Double
private let parameter2: Double
///
/// Capture the parameters you require for the Web Service call in your init
///
public init(webService: MyWebService, parameter1: Double, parameter1: Double) {
self.webService = webService
self.parameter1 = parameter1
self.parameter1 = parameter1
}
///
/// This will be executed by the container passing you an `ActionContext` to use for your database work.
///
func execute(context: ActionContext) throws {
guard !canceled else { return }
let (data, response, error) = webService.execute(request: MyWebServiceTask(parameter1: self.parameter1, parameter2: self.parameter2))
guard !canceled else { return }
if let response = response as? HTTPURLResponse {
switch response.statusCode {
case 200:
///
/// Process the returned data
///
break
default:
break
}
}
///
/// Errors can be thrown directly from actions. The container will
/// catch them and report them back through the notification system
/// and you completion block if one was supplied.
///
if let error = error {
throw error
}
}
}
源代码和二进制文件
您可以在 github 上找到最新的源代码和二进制文件。
沟通与贡献
- 如果您 发现了错误,并且可以提供可靠的复现步骤,请 打开一个问题。
- 如果您 有功能请求,请 打开一个问题。
- 如果您 想要贡献
- 分叉它! Coherence 仓库
- 创建您的特性分支:
git checkout -b my-new-feature
- 提交您的更改:
git commit -am '添加一些功能'
- pushes 到分支:
git push origin my-new-feature
- 提交 pull 请求 :-)
安装(CocoaPods)
Coherence 可通过 CocoaPods 获取。目前 Swift 是默认配置,要安装它,只需将以下行添加到您的 Podfile 中
pod "Coherence"
有关更多信息,请参阅 "Using CocoaPods" 指南。
最低要求
构建环境
平台 | Swift | Swift 构建 | Xcode |
---|---|---|---|
OSX | 4.2 | ✘ | 10.1 |
Linux | 不受支持 | ✘ | ✘ |
最低运行版本
iOS | OS X | tvOS | watchOS | Linux |
---|---|---|---|---|
9.0 | 10.13 | 9.0 | 2.0 | 不受支持 |
作者
Tony Stone (https://github.com/tonystone)
许可证
Coherence 在 Apache 许可证,版本 2.0 下发布