ZDCSyncable
为纯 Swift 中的结构体和类提供撤消、重做和合并功能。
作者:ZeroDark.cloud:一个安全同步和消息框架,基于区块链和 AWS 构建您的应用程序。
撤消和重做
示例 #1
import ZDCSyncable
struct Person: ZDCSyncable { // Just add ZDCSyncable protocol
@Syncable var name: String // Then add @Syncable property wrapper.
@Syncable var age: Int = 1 // And that's it!
}
// And now you get undo & redo support
let person = Person(name = "alice")
// ^ starting point
person.name = "bob"
person.age = 2
let changeset = person.changeset() // changes since starting point
do {
let redo = try person.undo(changeset!) // revert to starting point
// Current state:
// person.name == "alice"
// person.age == 1
let _ = try person.undo(redo) // redo == (undo an undo)
// Current state:
// person.name == "bob"
// person.age == 2
} catch _ {}
如果您想使用类而不是结构体,这也是支持的
示例 #2
import ZDCSyncable
class Animal: ZDCRecord { // <- Just extend ZDCRecord
@Syncable var species: String // And add @Syncable property wrapper.
@Syncable var age: Int
}
@Syncable
属性包装器适用于原始数据类型。
该框架还提供了一些额外的解决方案来替换集合类型
- ZDCArray
- ZDCDictionary
- ZDCOrderedDictionary
- ZDCSet
- ZDCOrderedSet
这些集合类型与原生的 Swift API 类似。并且它们都是作为结构体实现的,因此您会得到熟悉的价值语义。
示例 #3
import ZDCSyncable
struct Television: ZDCSyncable { // Add ZDCSyncable protocol
@Syncable var brand: String // Add @Syncable property wrapper.
// Or use syncable collection class:
var specs = ZDCDictionary<String, String>()
// ZDCDictionary has almost the exact same API as Swift's Dictionary.
// And ZDCDictionary is a struct, so you get the same value semantics.
}
var tv = Television(brand: "Samsung")
tv.specs["size"] = "30"
tv.clearChangeTracking() // set starting point
tv.brand = "Sony"
tv.specs["size"] = "40"
tv.specs["widescreen"] = "true"
let changeset = tv.changeset() // changes since starting point
do {
let redo = try tv.undo(changeset!) // revert to starting point
// Current state:
// tv.brand == "Samsung"
// tv.specs["size"] == "30"
// tv.specs["widescreen"] = nil
let _ = try tv.undo(redo) // redo == (undo an undo)
// Current state:
// tv.brand == "Sony"
// tv.specs["size"] == "40"
// tv.specs["widescreen"] = "true"
} catch _ {}
合并
您还可以合并更改! (例如从云端)
var localTV = Television(brand: "Samsung")
localTV.specs["size"] = "30"
localTV.clearChangeTracking() // set starting point
var cloudTV = localTV // Television is a struct
var changesets: [ZDCChangeset] = []
// local modifications
localTV.specs["size"] = "30.5"
localTV.specs["widescreen"] = "yes"
changesets.append(localTV.changeset() ?? ZDCChangeset())
// ^ pending local changes (not yet pushed to cloud)
// cloud modifications
cloudTV.specs["hdmi inputs"] = "2"
// Now merge cloud version into local.
// Automatically take into account our pending local changes.
do {
try localTV.merge(cloudVersion: cloudTV, pendingChangesets: changesets)
// Merged state:
// localTV.brand == "Samsung"
// localTV.specs["size"] == "30.5"
// localTV.specs["widescreen"] == "true"
// localTV.specs["hdmi inputs"] = "2"
} catch _ {}
入门指南
ZDCSyncable 可通过 CocoaPods 获取。
CocoaPods
请将以下内容添加到您的 Podfile 中
pod 'ZDCSyncable'
然后像往常一样运行 pod install
。然后您可以通过以下方式导入它
// Swift
import ZDCSyncable
推动因素
发生了合并冲突。如果您之前使用过 git,那么您会很熟悉这种情况。解决合并冲突需要知道改动了什么。这与数据模型也是一样的。
考虑一个简单的例子——同步一个朴实无华的字典。假设我们得知了一个冲突,但我们只知道以下这些
{
"local version": {
"size": "30.5",
"widescreen": "true"
},
"remote version": {
"size": "30",
"hdmi inputs": "2"
}
}
合并后的值应该是什么?
如果我们只使用上述信息,我们无法做出明智的决定
- 是谁更改了
size
属性?本地?远程?两者都更改了?谁胜出? - 远程是否删除了
widescreen
?还是本地添加了它? - 远程是否添加了
hdmi inputs
?还是本地删除了它?
ZDCSyncable 通过提供您所需的信息来帮助您解决合并冲突。它是通过跟踪更改并提供一个更改集来做到这一点的。
{
"local version": {
"size": "30.5",
"widescreen": "true"
},
"remote version": {
"size": "30",
"hdmi inputs": "2"
},
"local changeset": {
"size": {
"type": "changed",
"previous": "30"
},
"widescreen": {
"type": "added"
}
}
}
有了这些信息,合并就变得显而易见了
size
属性是本地更改的,远程没有更改。本地胜出widescreen
属性是本地添加的hdmi inputs
属性是由远程添加的
ZDCSyncable 项目为您提供了所需的工具
- 来跟踪数据模型的更改
- 在更改上传的过程中存储这些更改集
- 通过考虑本地更改集,正确地合并来自云端的更改
说实话,编写这些代码并不困难。这并不是火箭科学。但它确实需要进行大量的单元测试,以确保所有细微的边缘情况都正确无误。这意味着您可以选择自己编写所有的单元测试,或者使用一个已经由社区测试过的开源版本。(然后您可以用额外的时间使您的应用变得很棒。)