数据持久化(一)Core Data的简单使用

来源:互联网 发布:高大上的礼物知乎 编辑:程序博客网 时间:2024/04/30 09:55

写程序的过程一般都会涉及到数据的持久化保存,对于一个供用户使用的应用可以说是必备功能,保存数据的方法有几种:数据归档,写入磁盘文件,使用数据库,使用Core Data。

我也是最近才开始正式地接触Core Data,下面来说一下使用Core Data的学习过程。

写了两个简单的Demo来说一下其使用方法:

(一)SimpleCoreData_Demo:存取一些简单的数据类型

1.新建工程,使用Empty Application模板,点选使用Core Data选项:


和一般的工程的不同之处在于:

(1)工程自动加入了CoreData.framework:

(2)在工程中会生成一个xcdatamodeld文件:


(3)在委托类中自动生成以下代码:(在这里的注释参考了http://blog.csdn.net/ryantang03/article/details/7794226)

接口部分:

[cpp] view plaincopy
  1. #import <UIKit/UIKit.h>  
  2.   
  3. @interface AppDelegate : UIResponder <UIApplicationDelegate>  
  4.   
  5. @property (strong, nonatomic) UIWindow *window;  
  6.   
  7. @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; // 托管对象上下文  
  8. @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;     // 托管对象模型  
  9. @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; // 持久性存储区  
  10.   
  11. - (void)saveContext; // 保存上下文  
  12. - (NSURL *)applicationDocumentsDirectory; // 获取程序数据存放文档的路径  
  13.   
  14. @end  
实现部分:

[cpp] view plaincopy
  1. - (void)applicationWillTerminate:(UIApplication *)application  
  2. {  
  3.     // Saves changes in the application's managed object context before the application terminates.  
  4.     [self saveContext]; // 如果程序要退出则保存数据  
  5. }  
  6.   
  7. // 保存上下文  
  8. - (void)saveContext  
  9. {  
  10.     NSError *error = nil;  
  11.     NSManagedObjectContext *managedObjectContext = self.managedObjectContext; // 获取托管对象上下文  
  12.     if (managedObjectContext != nil) {  
  13.         if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {  
  14.              // Replace this implementation with code to handle the error appropriately.  
  15.              // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.  
  16.             // 如果保存数据时出错的处理动作  
  17.             NSLog(@"Unresolved error %@, %@", error, [error userInfo]);  
  18.             abort();  
  19.         }   
  20.     }  
  21. }  
  22.   
  23. #pragma mark - Core Data stack  
  24.   
  25. // Returns the managed object context for the application.  
  26. // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.  
  27. // 获取托管上下文对象  
  28. - (NSManagedObjectContext *)managedObjectContext  
  29. {  
  30.     if (_managedObjectContext != nil) {  
  31.         return _managedObjectContext;  
  32.     }  
  33.       
  34.     NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];  
  35.     if (coordinator != nil) {  
  36.         _managedObjectContext = [[NSManagedObjectContext alloc] init];  
  37.         [_managedObjectContext setPersistentStoreCoordinator:coordinator]; // 设置托管对象上下文管理的持久存储区  
  38.     }  
  39.     return _managedObjectContext;  
  40. }  
  41.   
  42. // Returns the managed object model for the application.  
  43. // If the model doesn't already exist, it is created from the application's model.  
  44. // 获取托管模型对象  
  45. - (NSManagedObjectModel *)managedObjectModel  
  46. {  
  47.     if (_managedObjectModel != nil) {  
  48.         return _managedObjectModel;  
  49.     }  
  50.       
  51.     // 获取SimpleCoreData_Demo.xcdatamodeld文件的路径  
  52.     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"SimpleCoreData_Demo" withExtension:@"momd"];  
  53.       
  54.     // 通过momd文件对应的模型初始化托管对象模型  
  55.     _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];   
  56.     return _managedObjectModel;  
  57. }  
  58.   
  59. // Returns the persistent store coordinator for the application.  
  60. // If the coordinator doesn't already exist, it is created and the application's store added to it.  
  61. // 获取持久性存储区  
  62. - (NSPersistentStoreCoordinator *)persistentStoreCoordinator  
  63. {  
  64.     if (_persistentStoreCoordinator != nil) {  
  65.         return _persistentStoreCoordinator;  
  66.     }  
  67.       
  68.     // 获取存储的数据库路径  
  69.     NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"SimpleCoreData_Demo.sqlite"];  
  70.       
  71.     NSError *error = nil;  
  72.       
  73.     // 通过托管对象模型初始化持久化存储区  
  74.     _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];  
  75.       
  76.     if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {  
  77.         /* 
  78.          Replace this implementation with code to handle the error appropriately. 
  79.           
  80.          abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.  
  81.           
  82.          Typical reasons for an error here include: 
  83.          * The persistent store is not accessible; 
  84.          * The schema for the persistent store is incompatible with current managed object model. 
  85.          Check the error message to determine what the actual problem was. 
  86.           
  87.           
  88.          If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. 
  89.           
  90.          If you encounter schema incompatibility errors during development, you can reduce their frequency by: 
  91.          * Simply deleting the existing store: 
  92.          [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] 
  93.           
  94.          * Performing automatic lightweight migration by passing the following dictionary as the options parameter: 
  95.          @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} 
  96.           
  97.          Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. 
  98.           
  99.          */  
  100.         NSLog(@"Unresolved error %@, %@", error, [error userInfo]);  
  101.         abort();  
  102.     }      
  103.       
  104.     return _persistentStoreCoordinator;  
  105. }  
  106.   
  107. #pragma mark - Application's Documents directory  
  108.   
  109. // Returns the URL to the application's Documents directory.  
  110. - (NSURL *)applicationDocumentsDirectory  
  111. {  
  112.     return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];  
  113.     // 例如:file:///Users/guo/Library/Application%20Support/iPhone%20Simulator/7.0/Applications/A4601DF3-A51D-4D42-B314-B3A63F5111C2/Documents/  
  114. }  
2.编辑xcdatamodeld文件,例如添加entity对象,为entity对象添加属性,设置entity属性之间的关系等。


在这里只是简单地添加了一个Data名的Entity,只有一个属性title,是NSString类型。

3.生成Entity对应的托管对象子类:


这样基本的存储数据模型就构建好了,可以在程序中对其进行操作。

4.在托管对象上下文中存取数据:

[cpp] view plaincopy
  1. #import <UIKit/UIKit.h>  
  2. #import "AppDelegate.h"  
  3.   
  4. @interface ViewController : UIViewController  
  5. @property (weak, nonatomic) IBOutlet UITextField *textField; // 输入Data类的title  
  6. - (IBAction)addData:(id)sender;   // 添加数据到数据库中  
  7. - (IBAction)queryData:(id)sender; // 查询数据库中的数据  
  8. @property (strong, nonatomic) AppDelegate *myDelegate; // 该视图控制器的委托类,用于获取本程序的Core Data相关类  
  9. @end  
  10.   
  11. - (void)viewDidLoad  
  12. {  
  13.     [super viewDidLoad];  
  14.       
  15.     // 首先获取本程序的委托,便于获取本程序的Core Data相关类对象  
  16.     self.myDelegate = [[UIApplication sharedApplication] delegate];  
  17.       
  18.     UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hideKeyboard:)];  
  19.     [self.view addGestureRecognizer:tap];  
  20. }  
  21.   
  22. - (void)didReceiveMemoryWarning  
  23. {  
  24.     [super didReceiveMemoryWarning];  
  25.     // Dispose of any resources that can be recreated.  
  26. }  
  27.   
  28. - (IBAction)addData:(id)sender {  
  29.     // 从托管对象上下文中获取Data类对象  
  30.     Data *data = (Data *)[NSEntityDescription insertNewObjectForEntityForName:@"Data" inManagedObjectContext:self.myDelegate.managedObjectContext];  
  31.     data.title = self.textField.text; // 设置data的title属性  
  32.       
  33.     NSError *error = nil;  
  34.     BOOL isSaveSuccess = [self.myDelegate.managedObjectContext save:&error]; // 保存修改后的托管对象上下文  
  35.       
  36.     if (isSaveSuccess && error == nil) {  
  37.         NSLog(@"Saving succeed");  
  38.     }  
  39.     else {  
  40.         NSLog(@"%@", error);  
  41.     }  
  42. }  
  43.   
  44. - (IBAction)queryData:(id)sender {  
  45.     // 创建Fetch请求  
  46.     NSFetchRequest *request = [[NSFetchRequest alloc] init];  
  47.     NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Data" inManagedObjectContext:self.myDelegate.managedObjectContext];  
  48.     [request setEntity:entityDescription]; // 设置请求对象为名为Data的Entity  
  49.       
  50.     // 对搜索结果进行排序  
  51.     NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:NO];  
  52.     NSArray *sortDescriptions = [[NSArray alloc] initWithObjects:sort, nil];  
  53.     [request setSortDescriptors:sortDescriptions];  
  54.       
  55.     NSError *error = nil;  
  56.     // 获取Fetch请求得到的结果,是一个数组  
  57.     NSArray *fetchResults = [self.myDelegate.managedObjectContext executeFetchRequest:request error:&error];  
  58.     if (fetchResults) {  
  59.         // 输出数组中各个元素的title  
  60.         for (Data *data in fetchResults) {  
  61.             NSLog(@"title:%@", data.title);  
  62.         }  
  63.     }  
  64.     else {  
  65.         NSLog(@"%@", error);  
  66.     }  
  67. }  
  68.   
  69. -(void)hideKeyboard:(id)sender  
  70. {  
  71.     [self.textField resignFirstResponder];  
  72. }  


Run一下:


控制台输出:

[cpp] view plaincopy
  1. 2013-08-27 15:02:02.416 SimpleCoreData_Demo[22382:a0b] Saving succeed  
  2. 2013-08-27 15:02:23.157 SimpleCoreData_Demo[22382:a0b] Saving succeed  
  3. 2013-08-27 15:02:38.511 SimpleCoreData_Demo[22382:a0b] Saving succeed  
  4. 2013-08-27 15:03:00.213 SimpleCoreData_Demo[22382:a0b] Saving succeed  
  5. 2013-08-27 15:03:06.096 SimpleCoreData_Demo[22382:a0b] Saving succeed  
  6. 2013-08-27 15:03:10.746 SimpleCoreData_Demo[22382:a0b] Saving succeed  
  7. 2013-08-27 15:03:12.460 SimpleCoreData_Demo[22382:a0b] title:title3  
  8. 2013-08-27 15:03:12.461 SimpleCoreData_Demo[22382:a0b] title:title2  
  9. 2013-08-27 15:03:12.461 SimpleCoreData_Demo[22382:a0b] title:title2  
  10. 2013-08-27 15:03:12.462 SimpleCoreData_Demo[22382:a0b] title:title1  
  11. 2013-08-27 15:03:12.464 SimpleCoreData_Demo[22382:a0b] title:title1  
  12. 2013-08-27 15:03:12.465 SimpleCoreData_Demo[22382:a0b] title:simple6  
  13. 2013-08-27 15:03:12.466 SimpleCoreData_Demo[22382:a0b] title:simple5  
  14. 2013-08-27 15:03:12.466 SimpleCoreData_Demo[22382:a0b] title:simple4  



(二)CodingCoreData_Demo:存取经过编码后的复杂数据类型

对于像NSArray和NSDictionary或者是一个类这样复杂的数据,如果要对其进行存取,则先要将其编码成NSData数据。其实任何数据都可以转化成NSData数据,然后再对其进行存取。

在本例中创建了一个名为BookData的Entity,其中BookData包含一个成员book,类型为NSData,用于保存一个Book类对象,该类有一个字典成员info。


由于要对Book类对象进行存取,所以该类必须遵守NSCoding协议并实现required方法:

[cpp] view plaincopy
  1. #import <Foundation/Foundation.h>  
  2.   
  3. @interface Book : NSObject <NSCoding> // 必须遵守NSCoding协议  
  4. @property (retain, nonatomic) NSMutableDictionary *info; // 属性字典  
  5. @end  
  6.   
  7.   
  8. #import "Book.h"  
  9.   
  10. @implementation Book  
  11.   
  12. // 必须实现initWithCoder:方法  
  13. -(id)initWithCoder:(NSCoder *)aDecoder  
  14. {  
  15.     self = [super init];  
  16.     if (self) {  
  17.         self.info = [aDecoder decodeObjectForKey:@"info"]; // 解码  
  18.     }  
  19.     return self;  
  20. }  
  21.   
  22. // 必须实现encodeWithCoder:方法  
  23. -(void)encodeWithCoder:(NSCoder *)aCoder  
  24. {  
  25.     [aCoder encodeObject:self.info forKey:@"info"]; // 编码  
  26. }  
  27.   
  28. @end  
下面是添加数据,抓取数据和删除所有存储好的数据的方法:

[cpp] view plaincopy
  1. @implementation ViewController  
  2.   
  3. - (void)viewDidLoad  
  4. {  
  5.     [super viewDidLoad];  
  6.       
  7.     self.myDelegate = [[UIApplication sharedApplication] delegate]; // 获取委托类  
  8. }  
  9.   
  10. - (void)didReceiveMemoryWarning  
  11. {  
  12.     [super didReceiveMemoryWarning];  
  13.     // Dispose of any resources that can be recreated.  
  14. }  
  15.   
  16. // 添加数据  
  17. - (IBAction)addData:(id)sender {  
  18.     // 从托管对象上下文中获取BookData名对应的Entity对象  
  19.     NSManagedObjectContext *context = [self.myDelegate managedObjectContext];  
  20.     NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"BookData" inManagedObjectContext:context];  
  21.     BookData *bd = [[BookData alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];  
  22.       
  23.     // 设置要保存的数据  
  24.     Book *book = [[Book alloc] init];  
  25.     NSDictionary *dic = @{@"name": self.name_textField.text,  
  26.                           @"charsPerPage": self.cpp_textField.text  
  27.                           };  
  28.     book.info = [dic mutableCopy]; // 设置book的字典info  
  29.     NSData *data = [NSKeyedArchiver archivedDataWithRootObject:book]; // 对book对象进行归档  
  30.     bd.book = data; // 设置bd的book对象(NSData类型)  
  31.       
  32.     // 保存数据到托管对象上下文中  
  33.     NSError *error = nil;  
  34.     BOOL isSaveSuccess = [context save:&error];  
  35.     if (isSaveSuccess) {  
  36.         NSLog(@"Save succeed");  
  37.     }  
  38.     else {  
  39.         NSLog(@"%@", error);  
  40.     }  
  41. }  
  42.   
  43. // 抓取数据  
  44. - (IBAction)fetchData:(id)sender {  
  45.     // 设置抓取请求的对象为名为BookData对应的Entity对象  
  46.     NSManagedObjectContext *moc = [self.myDelegate managedObjectContext];  
  47.     NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"BookData" inManagedObjectContext:moc];  
  48.     NSFetchRequest *request = [[NSFetchRequest alloc] init];  
  49.     [request setEntity:entityDescription];  
  50.       
  51.     // 抓取数据,返回结果为NSArray类型数据  
  52.     NSError *error = nil;  
  53.     NSArray *array = [NSMutableArray arrayWithArray:[moc executeFetchRequest:request error:&error]];  
  54.     if (array == nil || error != nil) {  
  55.         NSLog(@"Fetch result is nil");  
  56.     }  
  57.     else {  
  58.         for (BookData *bd in array) {  
  59.             Book *book = [NSKeyedUnarchiver unarchiveObjectWithData:bd.book]; // 对bd的book数据(NSData类型)解压  
  60.             NSLog(@"%@", book.info); // 输出字典信息  
  61.         }  
  62.     }  
  63. }  
  64.   
  65. // 删除所有保存的数据  
  66. - (IBAction)deleteData:(id)sender {  
  67.     /* 方法一:先抓取数据,然后遍历数组将其数据清空 
  68.     NSManagedObjectContext *moc = [self.myDelegate managedObjectContext]; 
  69.     NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"BookData" inManagedObjectContext:moc]; 
  70.     NSFetchRequest *request = [[NSFetchRequest alloc] init]; 
  71.     [request setEntity:entityDescription]; 
  72.     NSError *error = nil; 
  73.     NSArray *array = [NSMutableArray arrayWithArray:[moc executeFetchRequest:request error:&error]]; 
  74.     if (array == nil) { 
  75.         return; 
  76.     } 
  77.     else { 
  78.         for (NSManagedObject *item in array) { 
  79.             [moc deleteObject:item]; 
  80.         } 
  81.     } 
  82.      
  83.     [moc save:&error]; 
  84.     if (!error) { 
  85.         NSLog(@"Delete succeed"); 
  86.     } 
  87.     else { 
  88.         NSLog(@"%@", error); 
  89.     } 
  90.     */  
  91.       
  92.     // 方法二:在持久化存储区中移除存储数据的文件  
  93.     //Erase the persistent store from coordinator and also file manager.  
  94.     NSPersistentStore *store = [self.myDelegate.persistentStoreCoordinator.persistentStores lastObject];  
  95.     NSError *error = nil;  
  96.     NSURL *storeURL = store.URL;  
  97.     [self.myDelegate.persistentStoreCoordinator removePersistentStore:store error:&error];  
  98.     [[NSFileManager defaultManager] removeItemAtURL:storeURL error:&error];  
  99.       
  100.     NSLog(@"Delete succeed");  
  101.       
  102.     //Make new persistent store for future saves   (Taken From Above Answer)  
  103.     if (![self.myDelegate.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {  
  104.         // do something with the error  
  105.         NSLog(@"Delete error");  
  106.     }  
  107. }  
  108.   
  109. @end  

Run一下:


控制台输出:

[cpp] view plaincopy
  1. 2013-08-27 21:46:43.074 CodingCoreData_Demo[670:a0b] Save succeed  
  2. 2013-08-27 21:47:04.685 CodingCoreData_Demo[670:a0b] Save succeed  
  3. 2013-08-27 21:47:24.245 CodingCoreData_Demo[670:a0b] Save succeed  
  4. 2013-08-27 21:47:28.671 CodingCoreData_Demo[670:a0b] {  
  5.     charsPerPage = 1;  
  6.     name = "a.txt";  
  7. }  
  8. 2013-08-27 21:47:28.675 CodingCoreData_Demo[670:a0b] {  
  9.     charsPerPage = 2;  
  10.     name = "b.rtf";  
  11. }  
  12. 2013-08-27 21:47:28.677 CodingCoreData_Demo[670:a0b] {  
  13.     charsPerPage = 3;  
  14.     name = "c.pdf";  
  15. }  
  16. 2013-08-27 21:47:33.569 CodingCoreData_Demo[670:a0b] Delete succeed  
  17. 2013-08-27 21:47:47.095 CodingCoreData_Demo[670:a0b] Save succeed  
  18. 2013-08-27 21:48:00.653 CodingCoreData_Demo[670:a0b] Save succeed  
  19. 2013-08-27 21:48:07.565 CodingCoreData_Demo[670:a0b] Save succeed  
  20. 2013-08-27 21:48:09.471 CodingCoreData_Demo[670:a0b] {  
  21.     charsPerPage = 100;  
  22.     name = "book.txt";  
  23. }  
  24. 2013-08-27 21:48:09.472 CodingCoreData_Demo[670:a0b] {  
  25.     charsPerPage = 100;  
  26.     name = "book.rtf";  
  27. }  
  28. 2013-08-27 21:48:09.474 CodingCoreData_Demo[670:a0b] {  
  29.     charsPerPage = 100;  
  30.     name = "book.pdf";  
  31. }  


以上是Core Data存取数据的简单使用方法。

0 0
原创粉丝点击