一个 Swift Core Data 包装器,提供用于与托管对象和托管对象上下文交互的便捷 API。
如果您不希望使用上述任何一种依赖管理器,您可以将 SwiftyData 手动集成到项目中。
使用 SwiftyData 在文件顶部导入 SwiftyData
。
import SwiftyData
class Person: NSManagedObject {
@NSManaged var name: String
@NSManaged var age: Int64
}
如果您的模型名称与您的类名称不同,您应该覆盖 NSManagedObject
的 entityName
属性,并返回类的模型名称。
extension Person {
override class var entityName: String {
return "Human"
}
}
可选地,您可以采用和遵循 KeyCodeable
协议,这样您就可以使用枚举来表示您的属性,并确保类型安全。
extension Person: KeyCodeable {
enum Key: String {
case name
case age
}
}
// Create a Person
let person = Person.create() // No casting needed, just create!
person.name = "Foo"
person.age = 18
// Or you can just create with properties:
let person = Person.create([.name: "Foo", .age: 18])
// You can also create multiple instances all at once.
let people = Person.bulkCreate([.name: "Foo", .age: 19],
[.name: "Bar", .age: 29],
[.name: "Baz", .age: 32])
使用 NSManagedObjectContext
let context = NSManagedObjectContext.defaultContext()
context.create(Person)
context.create(Person.self, properties: [.name: "Foo", .age: 18])
所有在 NSManagedObject 子类上可用的方法也都在 NSManagedObjectContext 上可用。不同之处在于上下文接受一个作为第一个参数的类名称,在它上执行操作。
// Returns a dictionary of [String: AnyObject]
person.get([.name, .age])
// Set properties to new value
person.set([.name: "Bar", .age: 20])
// Deletes person
person.destroy()
// Deletes all Person
Person.destroyAll()
将对象或对象保存到持久存储库中。如果保存成功返回True
,否则返回False
。如果没有需要保存的更改在NSManagedObjectContext中,也返回False
。
// Saves person
let person = Person.create()
person.save() // true
person.save() // false
person.name = "Foo"
person.save() // true
// Same as calling
Person.save()
// Reloads person properties from the persistence store
let person = Person.create([.name: "Foo", .age: 18])
person.save()
person.set([.name: "Bar", .age: 20])
person.name // Baz
person.age // 20
person.reload()
person.name // Foo
person.age // 18
如果已经存在具有所提供属性的现有对象,则返回该对象,否则使用提供的属性创建一个新的对象。
Person.bulkCreate([.name: "Foo", .age: 19], [.name: "Bar", .age: 29])
Person.count() // returns 2
Person.upsert([.name: "Foo", .age: 19])
Person.count() // returns 2
Person.upsert([.name: "Baz", .age: 32])
Person.count() // returns 3
// Find all Person
// Returns an array of all person
Person.findAll()
// Find by id
let id = person.objectID
Person.findById(id)
// Find by NSURL
let url = perosn.objectID.URIRepresentation()
Person.findByNSURL(url)
// Finds one Person whose name is Foo
Person.findOne(where: [.name: "Foo"])
// You can a NSPredicate format string and arguments
// Finds one Person whose age is less than 20
Person.findOne(where: "age < %@", arguments: 20)
// Or you can just drop in a NSPredicate
// Finds one Person whose age is greater than 18
let predicate = NSPredicate(format: "age > 18")
Person.findOne(where: predicate)
// Finds all Person less than 30 years old
let lessThan30 = Person.find(where: "age < 30")
// Finds Person named Foo that has age 18
let foo = Person.find(where: "name == %@ AND age == %@", arguments: "Foo", 18)
// Finds Person named Bar that has age 20
let bar = Person.find(where: [.name: "Bar", .age: 20])
// Finds all Person greater than 18 years old
let predicate = NSPredicate(format: "age > 18")
let greaterThan18 = Person.find(where: predicate)
// Finds all Person and sort by name: ascending
Person.find(where: [:], sort: [.name: .ASC])
// You can pass in an array of NSSortDescriptor
// Finds all Person and sort by name and age
let byName = NSSortDescriptor(key: "name", ascending: false)
let byAge = NSSortDescriptor(key: "age", ascending: true)
let sorted = Person.find(where: "age > %@", arguments: 10, sort: [byName, byAge])
// Finds and return just two Person
let justTwo = Person.find(where: "age > 10", limit: 2)
Person.bulkCreate([.name: "Foo", .age: 19], [.name: "Bar", .age: 29], [.name: "Baz", .age: 32])
Person.save() // If context is not saved, the fetchOffset property of NSFetchRequest is ignored.
// Returns an array of Person object skipping the first two result
let skipTwo = Person.find(where: "age > %@", arguments: 10, skip: 2)
如果不在NSManagedObject子类上调用保存,则跳过的参数将被忽略。
// Returns a proxy object array of Person that transparently faults batches on demand.
Person.find(where: "age > %@", arguments: 10, batchSize: 2)
// Counts and return the number of Person
Person.count()
// You can supply a query to narrow down the objects to count
Person.count(where: "age < 30")
// You can also do this if you conform to KeyCodeable protocol
Person.count(where: [.name: "Foo"])
对于所有符合所提供查询的托管对象进行批量更新。返回类型为NSBatchUpdateRequestResultType,默认为StatusOnlyResultType。
// Updates all Person whose name begins with fo to Foo
Person.update(where: "name BEGINSWITH[cd] %@", arguments: "fo", with: [.name: "Foo"])
// You can specify a result type you prefer. Here we are
// specifying a result type which returns the number of updated objects
let updatedCount = Person.update(where: "age < 30", with: [.age: 30], resultType: .UpdatedObjectsCountResultType) as? Int
// You can supply a NSPredicate if you like.
let age = NSPredicate(format: "age == 30")
let name = NSPredicate(format: "name == %@", "Foo")
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [age, name])
Person.update(where: predicate, with:[.name: "Bar", .age: 19])
对于批量更新需要遵守KeyCodeable协议。
默认情况下,SwiftyData会将项目中目录下所有扩展名为xcdatamodeld
的Model文件合并。因此,不管你给模型命名什么,或者是否有多个模型文件,它们都将被找到。
如果您不希望这种行为,您可以在AppDelegate中明确设置SwiftyData要使用的模型文件名,并且只会使用这个文件。
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
SwiftyData.sharedData.modelName = "MyModel"
return true
}
您可以在从AppDelegate的application didFinishLaunchingWithOptions
方法返回之前设置一个数据库名,如果您不想使用默认的应用程序名称。
SwiftyData.sharedData.databaseName = "MyDatabase"
如果您不介意使用默认的,您也可以在从application didFinishLaunchingWithOptions
方法返回之前设置一个自定义的托管对象上下文。
let context = NSManagedObjectContext(concurrencyType: ...)
SwiftyData.sharedData.managedObjectContext = context
创建对象关系与设置它们的属性一样简单。考虑以下示例:
class Employee: Person {
@NSManaged var employmentDate: NSDate
@NSManaged var department: Department?
}
extension Employee {
enum Key: String {
case name, age, employmentDate, department
}
}
class Department: NSManagedObject {
@NSManaged var name: String
@NSManaged var employees: [Employee]
}
extension Department: KeyCodeable {
enum Key: String {
case name, employees
}
override class var entityName: String {
return "Organization"
}
}
let employee = Employee.create([.employmentDate: NSDate()])
let department = Department.create([.name: "Accounting", .employees: []])
employee.department // nil
department.employees.isEmpty // true
employee.department = department
employee.department // returns department
department.employees.isEmpty // false
employee.destroy()
employee.save()
department.employees.isEmpty // true
// You can supply related objects during initialization if you want
let employees = (1...20).map { Employee.create([.employmentDate: NSDate(timeIntervalSinceNow: NSTimeInterval($0))]) }
let department = Department.create([.name: "Health", .employees: employees])
department.employees.count // 20
Employee.find(where: "department == %@", arguments: department).count // 20
SwiftyData遵循MIT许可。有关更多信息,请参阅LICENSE.md文件。