PersistenceFramework 0.1.0

PersistenceFramework 0.1.0

Cristian Barril维护。



  • Cristian Barril

目录

PersistenceFramework

一个用面向协议编程来封装持久化逻辑的框架。这是一个示例框架,展示了如何使用

  • Cocoapods
  • 面向协议编程
  • 依赖注入
  • 单元测试

支持的数据库

  • Core Data
  • Realm

安装

使用 Cocoapods,在 Podfile 中添加:

所有数据库

pod 'PersistenceFramework'

仅核心数据数据库

pod 'PersistenceFramework/CoreData'

仅Realm数据库

pod 'PersistenceFramework/Realm'

如何使用

要使用此框架,您只需了解几个协议。这使得在数据库之间切换变得简单。

协议

DatabaseProtocol

这是任何数据库必须实现的基本协议。其想法是提供数据库应提供的最常用的功能。对于任何其他用途,您可以恢复数据库上下文并实现自定义代码。

public protocol DatabaseProtocol {
	...
    func create<ReturnType: DatabaseObjectTypeProtocol>() -> ReturnType?
    func recover<ReturnType: DatabaseObjectTypeProtocol>(key: String, value: String) -> [ReturnType]?
    func delete(_ object: DatabaseObjectType) -> Bool
    func getContext() -> DatabaseContextType
}

可保存协议

Core Data 中使用的可选协议。

public protocol Saveable {
    func save() throws
}

可更新协议

Realm 中使用的可选协议。

public protocol Updatable {
    func update<DatabaseObject: DatabaseObjectTypeProtocol>(_ object: DatabaseObject) -> Bool
}

注意: 这只是一个示例。您可以免费复制此存储库并创建自己的版本。

创建者

要创建或恢复数据库,您必须使用针对所需数据库的特定 DatabaseBuilder 结构。该结构需要用每个情况的必要信息进行初始化(Core Data 需要不同的事物,不同于 Realm)

Core Data 创建者

实例化此结构以创建 Core Data 数据库。您可以根据需要拥有任意多个。只需确保使用不同的 "名称"。

您需要提供的信息是

  • 数据库名称:带有数据库名称的字符串参数。
  • 捆绑包:NSManagedObjectModel 文件所在的位置的捆绑包,在迁移时需要。
  • 模型URL:NSManagedObjectModel 文件的路径的 URL。
public struct CoreDataBuilder: CoreDataBuilderProtocol {
    public typealias Database = CoreDataManager
    
    public let databaseName: String
    public let bundle: Bundle
    public let modelURL: URL
        
    public func create() throws -> CoreDataManager {
		...
    }
}

使用示例

let modelURL = Bundle.main.url(forResource: "MyModel", withExtension:"momd")
let databaseBuilder = CoreDataBuilder(databaseName: "CoreDataDatabaseName", bundle: Bundle.main, modelURL: modelURL)
let database = try? databaseBuilder.create() as CoreDataManager

Realm 创建者

实例化此结构以创建 Realm 数据库。您可以根据需要拥有任意多个。只需确保使用不同的 "名称"。

您需要提供的信息是

  • 数据库名称:带有数据库名称的字符串参数。
  • 密码短语:用于加密数据库的字符串密钥。不能为空字符串。
  • 版本号:包含当前版本号的 Uint64。默认值为 0。(可选参数)
  • 迁移块:当模型更改时需要迁移块。默认值为 nil。(可选参数)
public struct RealmBuilder: RealmBuilderProtocol {
    public typealias Database = RealmManager
    
    public let databaseName: String
    public let passphrase: String
    public let schemaVersion: UInt64
    public let migrationBlock: MigrationBlock?
    
    public func create() throws -> RealmManager {
	    ...
    }
}

使用示例

let databaseBuilder = RealmBuilder(databaseName: "RealmDatabaseName", passphrase: "Passphrase")
let database = try? databaseBuilder.create() as RealmManager

注意: 这只是一个示例。您可以免费复制此存储库并创建自己的版本。

使用

常规

创建

创建新用户实体的示例

let newObject: User? = database.create()

恢复

恢复所有用户实体的示例

let recoveredObjects: [User]? = database.recover()

恢复特定用户实体的示例。可以用任何属性,因此返回一个数组。例如:返回所有名为“John”的用户

let recoveredObjects: [User]? = database.recover(key: "name", value: "John")

删除

删除特定用户实体的示例。如果操作成功返回true,如果失败返回false

let result = database.delete(objectToDelete)

核心数据

保存

自定义Core Data方法保存上下文

try? database.save()

Realm

更新

自定义Realm方法更新特定 用户 实体。如果操作成功返回true,否则返回false

let result = database.update(newObject)

添加自定义代码

要使用数据库的其他功能,您可以恢复上下文并使用它

let context = database.getContext()

迁移

Core Data

  • 轻量级迁移:只需要像往常一样初始化数据库,框架会自动迁移。

  • 重量级迁移:需要在数据库的同一体中创建一个NSMappingModel来完成。如果有需要,在NSMappingModel中也可以设置一个NSEntityMigrationPolicy类型类,并为迁移过程添加自定义逻辑。

Realm

当模型更改时,您需要遵循以下步骤

  • 提高模式版本
  • 在Builder结构中创建迁移块。下面有一些示例
migrationBlock: { migration, oldSchemaVersion in
                if (oldSchemaVersion < 1 && self.lastSchemaVersion >= 1) {
                    print("Automatic migration")
                    // Nothing to do!
                    // Realm will automatically detect new properties and removed properties
                    // And will update the schema on disk automatically
                }
                
                if (oldSchemaVersion < 2 && self.lastSchemaVersion >= 2) {
                    // The enumerateObjects(ofType:_:) method iterates
                    // over every Person object stored in the Realm file
                    migration.enumerateObjects(ofType: Person.className()) { oldObject, newObject in
                        // combine name fields into a single field
                        let firstName = oldObject!["firstName"] as! String
                        let lastName = oldObject!["lastName"] as! String
                        newObject!["fullName"] = "\(firstName) + \(lastName)"
                    }
                }
                
                if (oldSchemaVersion < 3 && self.lastSchemaVersion >= 3) {
                    // The renaming operation should be done outside of calls to `enumerateObjects(ofType: _:)`.
                    migration.renameProperty(onType: Person.className(), from: "age", to: "yearsSinceBirth")
                }
            }