
下面的讨论以使用core data来做数据持久化并使用sqlite做backend存储的情况为前提。
使用方便性。实际上,一个成熟的工程中一定是对数据持久化进行了封装的,因此底层使用的到底是core data还是sqlite,不应该被业务逻辑开发者关心。因此,即使习惯写SQL查询的人,也应该避免在业务逻辑中直接编写SQL语句。
存储性能,在写入性能上,因为都是使用的sqlite格式作为磁盘存储格式,因此其性能是一样的,如果你觉得用core data写的慢,很可能是你用sqlite的时候写的每条数据的内容没有core data时多,或者是你批量写入的时候每写入一条就调用了一次save。
查询性能,core data因为要兼容多种后端格式,因此查询时,其可用的语句比直接使用sqlite少,因此有些fetch实际上不是在sqlite中执行的。但这样未必会降低查询效率。因为iPhone的flash memory速度还是很快的。我的经验是大部分时候,在内存不是很紧张时,直接fetch一个entity的所有数据然后在内存中做filter往往比使用predicate在fetch时过滤更快。如果你觉的查询慢,很可能是查询方式有问题,可以把core data的debug模式打开,看一下到底执行了多少SQL语句,相信其中大部分是可以通过改写core data的调用方式避免的。
core data的一个比较大的痛点是多人合作开发的时候,管理coredata的模型需要很小心,尤其是合并的时候,他的data model是XML格式的,手动resolve比较烦心。
core data还有其他sql所不具备的优点,比如对undo的支持,多个context实现sketchbook类似的功能。为ManagedObject优化的row cash等。
另外core data是支持多线程的,但需要thread confinement的方式实现,使用了多线程之后可以最大化的防止阻塞主线程
Realm是一个开源的面向对象移动数据库。上个月,Realm的Android版本发布了,比iOS版本晚了三个月。我们之前已经报道过,Realm没有使用SQLite作为它的引擎,而是用C++写了自己的引擎,他们的目标是提供一个聚焦移动领域的SQLite的替代者。现在它的Android版本已经发布了。
当前Android上的Realm的API和iOS版本有点不同,这也反映了Objective C和Java的差别。Java版本的API有更高的强类型(strong-typed)要求,也更连贯(fluent)。
比如,在iOS上,查询是通过静态方法如"objectWhere"来进行的,这将返回一个RLMArray。这里的谓词都是基于字符串的。以下就是基于Object C的查询方法:
RLMArray *tanDogs = [Dog objectsWhere:@"color = 'tan' AND name BEGINSWITH 'B'"]
另一方面,在Android下进行相同的查询却是这样的:
RealmResults<Dog>tanDogs = realm.where(Dog.class)
.equalTo("color", "tan")
.beginsWith("name", "B")
.findAll()
当然,这有可能会被一种跨iOS、Android和其他平台的文本查询语言所替代。Tim Anglade是Realm的产品主管,他在一封邮件中指出,未来API的发展方向很大程度取决于社区的反馈。
虽然Realm是一个面向对象的数据库,但它和其他同类产品还是有一些明显的不同。Tim解释道,当它用原生对象格式(native object format)来存储数据时,这些对象不会带着其语言特有的格式原封不动地存在磁盘上,而是通过C++引擎存储在一个全局的表中。这使得Realm可以通过各种语言来访问数据,还包括各种即时查询(adhoc query)。
相比关系数据库,这种混合了对象和表的方式的优势在于它使图查询(graph query)更高效——甚至在相对老旧的智能手机上,查询深度嵌套的对象图也不会影响系统反应速度。Realm发布的基准测试(benchmark)结果称,在普通 *** 作上,Realm的速度最快要达到原始的SQLite的10倍。
如果你现在有一个应用程序使用CoreData(iOS上)或SQLite(Android上),并且想迁移到Realm,肯定有一些事要做。这不是随便拿来就能用的——Tim解释说,CoreData和SQLite倾向于使用一种非常标准化的形式,这种做法在Realm上行不通。你最好从对象的角度重新思考你的模式(schema)和模型(model)。
一旦你修改了你的模式,使之适用于Realm,接下来把现有数据从CoreData/SQLite迁移过来就简单了。只要配置一次迁移 *** 作(从Realm数据库版本0到版本1),在迁移过程中,把你的SQLite数据加载到Realm对象中并保存它们。
或者,如果你的数据保存在远程服务器上,你可以从头新建Realm数据库。
在采用Realm之前,必须要考虑到它是一个最前沿的软件,这意味着将来它的API有可能做出和以前不兼容的修改。
你可以通过Android版本的Realm来了解更多,或者查看Github上的代码。
第一步:创建一个 DataDemo.xcdatamodel 文件,在其中建一个实体名字为 Entity1 ,实体中建两个字段 id 和 name。第二步:为项目添加 CoreData.framework 框架,然后在 .pch 中加入 #import <coredata/coredata.h>
第三步:在 app delegate 中定义 core data 的相关对象(同时完成它们的初始化工作)
.h 文件:
#import <coredata/coredata.h>
@private
NSManagedObjectModel *managedObjectModel
NSManagedObjectContext *managedObjectContext
NSPersistentStoreCoordinator *persistentStoreCoordinator
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator
- (NSString*) applicationDocumentsDirectory
- (void) saveContext
.m 文件:
@synthesize managedObjectModel
@synthesize managedObjectContext
@synthesize persistentStoreCoordinator
- (void)dealloc {
[managedObjectModel release]
[managedObjectContext release]
[persistentStoreCoordinator release]
[super dealloc]
}
- (NSString*)applicationDocumentsDirectory
{
//return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)
NSString *basePath = ([paths count] >0) ? [paths objectAtIndex:0] : nil
return basePath
//return [NSURL URLWithString:basePath]
}
- (void)saveContext{
NSError *error = nil
NSManagedObjectContext *objectContext = self.managedObjectContext
if (objectContext != nil)
{
if ([objectContext hasChanges] &&![objectContext save:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo])
abort()
}
}
}
- (NSManagedObjectContext *)managedObjectContext
{
if (managedObjectContext != nil) {
return managedObjectContext
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init]
[managedObjectContext setPersistentStoreCoordinator:coordinator]
}
return managedObjectContext
}
- (NSManagedObjectModel *)managedObjectModel
{
if (managedObjectModel != nil) {
return managedObjectModel
}
//从本地所有 xcdatamodel 文件中获得这个 CoreData 的数据模板
managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]
return managedObjectModel
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator
}
//数据库名为TestDB.sqlite
NSURL *storeUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"TestDB.sqlite"]]
NSError *error
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nilURL:storeUrl options:nil error:&error]) {
NSAssert(0, @"persistentStoreCoordinator init failed!")
}
return persistentStoreCoordinator
}
- (void)applicationWillTerminate:(UIApplication *)application
{
NSError *error
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] &&![managedObjectContext save:&error]) {
NSAssert(0, @"save changes failed when terminage application!")
}
}
}
第四步:在相关的 viewcontroller 中 *** 作数据,基本的 core data *** 作代码如下:
NSError *error
testSQLiteAppDelegate *app = (testSQLiteAppDelegate*)[[UIApplication sharedApplication] delegate]
NSManagedObjectContext *context = app.managedObjectContext
//1、插入
NSManagedObject *newManagedObject = nil
newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"Entity1" inManagedObjectContext:context]
[newManagedObject setValue:[NSNumber numberWithInt:1] forKey:@"id"]
[newManagedObject setValue:@"i love you" forKey:@"name"]
if (![context save:&error]){
NSLog (@"The error is: %@", [error userInfo])
}
else
{
NSLog (@"The newManagedObject's id is: %@", [newManagedObject valueForKey:@"id"])
}
//2、查询
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Entity1" inManagedObjectContext:context]
NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"id" ascending:YES]
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor1, sortDescriptor2, nil]
[fetchRequest setSortDescriptors:sortDescriptors]
[fetchRequest setEntity:entity]
[fetchRequest setFetchBatchSize:20]
NSArray *objects = [context executeFetchRequest: fetchRequest error:&error]
if (objects == nil)
{
NSLog(@"There was an error!")
}
else {
for (NSManagedObject *oneObject in objects)
{
NSLog(@"%@",[oneObject valueForKey:@"name"])
}
}
//3、删除
[context deleteObject:[objects objectAtIndex:0]]
if (![context save:&error]) {
exit(-1)
}
这里更详细的补充一点关于 core data 的 *** 作代码:
1、条件过滤:选择 cid=1 的数据
- (NSFetchedResultsController*) fetchedResultsController
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"cid=1"]
[fetchRequest setPredicate:predicate]
}
2、通用代码,在 viewcontroller 里面会用到:
TestViewController.h 的代码:
@interface TestViewController : UITableViewController <NSFetchedResultsControllerDelegate>
{
NSFetchedResultsController *fetchedResultsController
NSManagedObjectContext *managedObjectContext
}
@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext
- (void)configureCell:(UITableViewCell *)cell withCategory:(Category *)category
@end
TestViewController.m 的代码:
-(NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController != nil)
{
return fetchedResultsController
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:managedObjectContext]
[fetchRequest setEntity:entity]
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES]
NSArray *arraySortDescriptor = [[NSArray alloc] initWithObjects:nameDescriptor, nil]
[fetchRequest setSortDescriptors:arraySortDescriptor]
NSPredicate *predicate = [NSPredicate predicateWithFormat:cidString]
[fetchRequest setPredicate:predicate]
NSFetchedResultsController *frController = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:@"name" cacheName:@"Root"]
frController.delegate = self
self.fetchedResultsController = frController
[frController release]
[fetchRequest release]
[nameDescriptor release]
return fetchedResultsController
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)
{
[self.tableView beginUpdates]
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType: (NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView
switch (type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]
break
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]
break
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]
break
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] withCategory:anObject]
break
default:
break
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]
break
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade]
break
}
}
- (void) controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates]
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)