Core Data 是一个强大的框架,用于管理 iOS 和 macOS 应用程序的数据模型。它可以帮助开发者快速地创建和维护数据库,并且可以轻松地将数据存储在本地文件中。Core Data 提供了一个面向对象的方法来管理数据,使得开发者可以快速而有效地处理大量的数据。
Core Data 的核心是一个关系型数据库,它使用 SQLite 作为存储引擎。它允许开发者将多个表格连接起来,并使用 SQL 语句来执行复杂的数据库查询。此外,Core Data 还包含一些高级功能,如对象图形映射 (Object Graph Mapping)、内存管理 (Memory Management) 和性能优化 (Performance Optimization) 等。
// 创建 Core Data Stack let persistentContainer = NSPersistentContainer(name: "MyDataModel") persistentContainer.loadPersistentStores { (description, error) in if let error = error { fatalError("Unresolved error \(error)") } } // 获取上下文对象 let context = persistentContainer.viewContext // 创建新的实体对象 let newEntity = NSEntityDescription.insertNewObject(forEntityName: "MyEntity", into: context) as! MyEntity // MyEntity 是你创建的实体名称 // 这里你可以保存新创建的实体对象 try context.save() // 查询所有实体对象 let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "MyEntity") do { let results = try context.fetch(fetchRequest) for result in results as! [NSManagedObject] { print("result: \(result)") } } catch { print("Error fetching data") }
原文出处: http://chengway.in/post/ji-zhu/core-data-by-tutorials-bi-ji-er
今天继续来重温Raywenderlich家的《Core Data by Tutorials》。学完前三章就掌握了CoreData的基本知识,现在我们来深入来研究下Fetching?
这一章主要深入地探究Fetching,学完这一章,你将会加满如下技能点:
还是按作者的主要目录来梳理一下吧:
明星登场,同样是创建NSFetchRequest的实例,并对其进行configure且执行。总而言之,繁重的工作都替你干了,任劳任怨的程度和NSManagedObjectContext有一拼。接着展示了四种创建NSFetchRequest实例的方式:
//1
let fetchRequest1 = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedObjectContext!)
let entity = NSEntityDescription.entityForName("Person", inManagedObjectContext: managedObjectContext!)
//2
let fetchRequest2 = NSFetchRequest(entityName: "Person")
//3
let fetchRequest3 = managedObjectModel.fetchRequestTemplateForName("peopleFR")
//4
let fetchRequest4 = managedObjectModel.fetchRequestFromTemplateWithName("peopleFR", substitutionVariables: ["NAME" : "Ray"])
本章要实现一个泡泡?茶的APP,作者提供了一个Start project,快速浏览一下,主界面是一个TableView,奶茶店等原始数据都保存seed.json之中。接下来要考虑如何将数据从seed中读取到Core Data的对象中去。
这里可以在data model中设置一个Fetch Request,并选择Fetch哪些对象,设置一些条件;紧接着你就可以使用模板中fetchRequest了:
fetchRequest = coreDataStack.model.fetchRequestTemplateForName("FetchRequest")
这里要使用coreData,并注意FetchRequest名称要和model中的匹配。
作者把NSFetchRequest比喻成了Core Data framework中的瑞士军刀,看来还是相当强大的。这里有四种fetch request的result type:
①.NSManagedObjectResultType: Returns managed objects (default value).
②.NSCountResultType: Returns the count of the objects that match the fetch request.
③.NSDictionaryResultType: This is a catch-all return type for returning the results of different calculations.
④.NSManagedObjectIDResultType: Returns unique identifiers instead of full- fledged managed objects.
将fetchRequest.resultType设为NSCountResultType在查询大量对象数量时可以极大的优化性能。
另一种获取count的方式是context直接调用countForFetchRequest方法
let count = coreDataStack.context.countForFetchRequest(fetchRequest, error: &error)
Core Data提供了多种函数支持来支持计算,如average, sum, min and max. 下面是一个求和的例子:
func populateDealsCountLabel() {
//1 指定result类型
let fetchRequest = NSFetchRequest(entityName: "Venue") fetchRequest.resultType = .DictionaryResultType
//2 创建表达式描述,指定个名称,以便将来在fetch的结果(字典类型)中找到
let sumExpressionDesc = NSExpressionDescription() sumExpressionDesc.name = "sumDeals"
//3 创建具体的表达式
sumExpressionDesc.expression = NSExpression(forFunction: "sum:", arguments:[NSExpression(forKeyPath: "specialCount")])
sumExpressionDesc.expressionResultType = .Integer32AttributeType
//4 设置fetch request 将要fetch sum
fetchRequest.propertiesToFetch = [sumExpressionDesc]
//5 执行,最后通过之前设置的表达式name得到最终结果
var error: NSError?
let result = coreDataStack.context.executeFetchRequest(fetchRequest, error: &error) as [NSDictionary]?
if let resultArray = result {
let resultDict = resultArray[0]
let numDeals: AnyObject? = resultDict["sumDeals"] numDealsLabel.text = "(numDeals!) total deals"
} else {
println("Could not fetch (error), (error!.userInfo)")
}
}
现在还剩一种.ManagedObjectIDResultType类型,他返回一个包含NSManagedObjectID对象的数组,NSManagedObjectID 可以看成是managed object通用唯一标识,除了多线程的某些场景下,否则很少用到它。
关于性能优化CoreData通过以下几种方式来削减income data:
①.fetch batches,可以使用fetchBatchSize, fetchLimit 和 fetchOffset这些属性来削减income data。
②.支持**faulting**这样的*占位符*。
③.使用predicates
最后要注意一下如果想要在运行时改变predicate,就不能再用model来初始化fetchRequest了
override func viewDidLoad() {
super.viewDidLoad()
// fetchRequest = coreDataStack.model.fetchRequestTemplateForName("FetchRequest")
fetchRequest = NSFetchRequest(entityName: "Venue") fetchAndReload()
}
至于predicates的用法请查看官方文档
排序主要用到了NSSortDescriptor这个类,值得注意的是该排序是真正发生在SQLite层面的,而不是在内存中的,因此该排序十分高效。
NSSortDescriptor实例初始化需要三个参数:①.你要排序属性的key path ②.指明升序 or 降序 ③. 一个可选的selector
这里要注意一点就是CoreData不支持block-based API定义NSSortDescriptor,以及基于block-based方式定义NSPredicate。
//下面两个初始化方法不能用于CoreData中
+ (instancetype)sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending comparator:(NSComparator)cmptr
+ (NSPredicate *)predicateWithBlock:(BOOL (^)(id evaluatedObject, NSDictionary *bindings))block
下面创建了一个按名字排序filter
lazy var nameSortDescriptor: NSSortDescriptor = {
var sd = NSSortDescriptor(key: "name",
ascending: true,
selector: "localizedStandardCompare:")
return sd
}()
这里注意一下第三个参数localizedStandardCompare,传入这个参数就会按本地语言排序,这也是苹果官方推荐的一种做法。
得到一个反转排序的sortDescriptor也很简单,这样就可以了
selectedSortDescriptor = nameSortDescriptor.reversedSortDescriptor
iOS 8苹果推出全新的API来处理异步fetch问题,NSAsynchronousFetchRequest,这里不要被他的名字迷惑了,和NSFetchRequest没什么直接关系,他其实是NSPersistentStoreRequest的子类。下面是该类的定义及初始化方法:
@availability(iOS, introduced=8.0)
class NSAsynchronousFetchRequest : NSPersistentStoreRequest {
var fetchRequest: NSFetchRequest { get }
var completionBlock: NSPersistentStoreAsynchronousFetchResultCompletionBlock? { get }
var estimatedResultCount: Int
init(fetchRequest request: NSFetchRequest, completionBlock blk: NSPersistentStoreAsynchronousFetchResultCompletionBlock?)
}
从该类的初始化方法可以将异步fetchRequest看做是对fetchRequest的一种包装,第一个参数是标准的NSFetchRequest 对象,而第二个参数是一个a completion handler,不过仅仅有completion handler是不够的,最后还是需要executeRequest,下面是一个完整的例子:
//1
fetchRequest = NSFetchRequest(entityName: "Venue")
//2
asyncFetchRequest = NSAsynchronousFetchRequest(fetchRequest: fetchRequest) {
[unowned self] (result: NSAsynchronousFetchResult! ) -> Void in
self.venues = result.finalResult as [Venue]
self.tableView.reloadData()
}
//3
var error: NSError?
let results = coreDataStack.context.executeRequest(asyncFetchRequest, error: &error)
if let persistentStoreResults = results {
//Returns immediately, cancel here if you want
} else {
println("Could not fetch (error), (error!.userInfo)")
}
这段代码注意executeRequest一旦执行立即返回一个NSAsynchronousFetchResult类型的结果,在这里你不用操心fetch到的数据和UI匹配,这些工作都在第二步handle那里处理了。另外NSAsynchronousFetchResult是有cancel()方法的。
仅仅有新API还不够,还要修改context
context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
另外一种.PrivateQueueConcurrencyType将在后面多线程介绍
因为是异步fetch,所以可能tableview初始化完毕后,fetch的结果才到,这里给数据源可以设置一个空数组来fix。
有的时候你需要一次更新很多属性,全部fetch到内存显然是不高效的,iOS 8推出了全新的批量更新(batch updates)来解决这一痛点。这个类就是NSBatchUpdateRequest,和上面提到的NSAsynchronousFetchRequest都是NSPersistentStoreRequest的子类,下面是这个类的定义:
@availability(iOS, introduced=8.0)
class NSBatchUpdateRequest : NSPersistentStoreRequest {
init(entityName: String)
init(entity: NSEntityDescription)
var entityName: String { get }
var entity: NSEntityDescription { get }
var predicate: NSPredicate?
// Should the update include subentities? Defaults to YES.
var includesSubentities: Bool
// The type of result that should be returned from this request. Defaults to NSStatusOnlyResultType
var resultType: NSBatchUpdateRequestResultType
// Dictionary of NSPropertyDescription|property name string -> constantValue/NSExpression pairs describing the desired updates.
// The expressions can be any NSExpression that evaluates to a scalar value.
var propertiesToUpdate: [NSObject : AnyObject]?
}
具体使用起来也很简单:
let batchUpdate = NSBatchUpdateRequest(entityName: "Venue")
batchUpdate.propertiesToUpdate = ["favorite" : NSNumber(bool: true)]
batchUpdate.affectedStores = coreDataStack.psc.persistentStores
batchUpdate.resultType = .UpdatedObjectsCountResultType
var batchError: NSError?
let batchResult = coreDataStack.context.executeRequest(batchUpdate, error: &batchError) as NSBatchUpdateResult?
if let result = batchResult {
println("Records updated (result.result!)")
} else {
println("Could not update (batchError), (batchError!.userInfo)")
}
最后注意一点,就是批量更新跳过了NSManagedObjectContext,直接对persistentStore进行更新,没有经过有效性验证,这个就要靠你自己确保更新的数据合法了。
原文:http://www.aosabook.org/en/nginx.html作者: Andrew Alexeevnginx(发音"engine x")是俄罗斯软件工程师Igor Sysoev开...
Preface:这篇文章是在图灵社区中接受的第一份翻译工作 ---- 翻译AOSA(The Architecture of Open Source Application),目的是:在...
jQuery removeClass() 方法jQuery HTML/CSS 方法实例 从所有的 p 元素移除 intro 类:$(button).click(function(){ $(p).removeC...
jQuery first() 方法jQuery 遍历方法实例 选取第一个 div 元素内的第一个 p 元素:$(div p).first()定义和用法 first() 方法返回...
jQuery slice() 方法jQuery 遍历方法实例 从带有索引号为 2 的 p 元素开始选中 p 元素:$(p).slice(2)定义和用法 slice() 方法选...