日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

iOS CoreData

 最初九月雪 2015-01-30

  我目前的理解,CoreData相當(dāng)于一個綜合的數(shù)據(jù)庫管理庫,它支持sqlite,二進(jìn)制存儲文件兩種形式的數(shù)據(jù)存儲。而CoreData提供了存儲管理,包括查詢、插入、

刪除、更新、回滾、會話管理、鎖管理等一系列數(shù)據(jù)庫操作。另外,開發(fā)者還可以在xcode中使用 .xcdatamodel 擴(kuò)展名的文件,以圖形化的形式編輯數(shù)據(jù)模型,這里包括了

Entities、Properties、Attributes、Relationships四個概念,這里跟關(guān)系型數(shù)據(jù)庫有很大的相似點。

                  下面來看一下CoreData的框架。

                一次來了解一下 PersistentStore、DataModel、PersistentStoreCoordinator、ManagedObjects、ManagedObjectsContext、FetchRequest 這些概念。

                PersistentStore

                            這個是數(shù)據(jù)真正存儲的地方,CodeData提供了兩種存儲的選擇,分別是sqlite和二進(jìn)制文件。PersistentStore本身并不是objc類,僅僅是數(shù)據(jù)存儲。

               DataModel

                              對應(yīng)的objc類為 NSManagedObjectModel,一個典型的應(yīng)用如:

 

  1. /** 
  2. Returns the managed object model for the application. 
  3. If the model doesn't already exist, it is created by merging all of the models 
  4. found in the application bundle. 
  5. */  
  6. - (NSManagedObjectModel *)managedObjectModel {  
  7. if (managedObjectModel != nil) {  
  8. return managedObjectModel;  
  9. }  
  10. managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];  
  11. return managedObjectModel;  
  12. }  
這里用了iPhone開發(fā)中典型的laze loading,而
  1. managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];  

中的nil表示連接項目中所有的 .xcodemodel 文件為一個datamodel,這是一個非常好的方法,把多個entity放在各自的xcodemodel文件中分開管理,然后用這個函數(shù)連接起來生成一個datamodel,這樣就可以對應(yīng)一個persistentStore。

PersistentStoreCoordinator

     對應(yīng)的objc類為NSPersistentStoreCoordinator,這個類用來控制對PersistentStore的訪問。PersistentStoreCoordinator提供了一些列的高級調(diào)用供其他類來使用,對PersistentStore進(jìn)行讀和寫。下面看一段典型的代碼:

 

  1. /** 
  2. Returns the persistent store coordinator for the application. 
  3. If the coordinator doesn't already exist, it is created and the application's store 
  4. added to it. 
  5. */  
  6. - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {  
  7.     if (persistentStoreCoordinator != nil) {  
  8.         return persistentStoreCoordinator;  
  9.     }  
  10.     NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]  
  11.     stringByAppendingPathComponent: @"CoreData.sqlite"]];  
  12.     NSError *error;  
  13.     persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]  
  14.     initWithManagedObjectModel: [self managedObjectModel]];  
  15.     if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType  
  16.     configuration:nil URL:storeUrl options:nil error:&error]) {  
  17.     // Handle error  
  18.     }  
  19.     return persistentStoreCoordinator;  
  20. }  
這里默認(rèn)存儲形式為sqlite,并且存儲文件為CoreData.sqlite,這段代碼比較簡單,創(chuàng)建了persistentStoreCoordinator實例。

 

ManagedObjects

    對應(yīng)的類為NSManagedObject。上面的CoreData框架圖中有Entities,Entity定義了數(shù)據(jù)的結(jié)構(gòu),但他并不是數(shù)據(jù),真正的數(shù)據(jù)實例是NSManagedObject類或他的子類。

    NSManagedObject類支持Key-Value 編碼(KVC),像NSDictionary差不多。NSManagedObject提供了valueForKey:和setValue:forKey:用來設(shè)置和查詢的方法。另外他也提供了對關(guān)系操作的方法。

   下面是幾個典型的代碼案例:

 

  1. NSDate *timeStamp = [managedObject valueForKey:@"timeStamp"];  

  1. [managedObject setValue:[NSDate date] forKey:@"timeStamp"];  

另外KVC也支持keypath,如有兩個數(shù)據(jù)entity,一個是Employee,一個事Employer,Employee中有個屬性石whereIWork,而這個屬性用relationship連接到了對應(yīng)的Employer,Employer中有個屬性石name,這樣要查詢一個Employer的name,可以用keypath的形式,whereIWork.name。

 

 

  1. NSString *employerName = [managedObject valueForKeyPath:@"whereIWork.name"];  

 

ManagedObjectsContext

    對應(yīng)的類為NSManagedObjectsContext。 這個類是一個用戶對persistentStore操作的網(wǎng)關(guān),他維護(hù)了用戶創(chuàng)建或者加載的managed objects。他記錄了用戶對managed objects的所有改變,以便用來undo或redo,另外當(dāng)用戶要存儲現(xiàn)在的managed objects到persistentstore時,只需調(diào)用managedObjectsContext的save方法就行了。

    每個應(yīng)用至少需要一個context,當(dāng)然可以同時存在多個context,比如多線程時,如NSOperationQueue。context并不是線程安全的,因此在這種情況中用戶要自己做好安全工作。

    下面是一個簡單應(yīng)用實例。

  1. /** 
  2. Returns the managed object context for the application. 
  3. If the context doesn't already exist, it is created and bound to the persistent 
  4. store coordinator for the application. 
  5. */  
  6. - (NSManagedObjectContext *) managedObjectContext {  
  7.     if (managedObjectContext != nil) {  
  8.         return managedObjectContext;  
  9.     }  
  10.     NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];  
  11.     if (coordinator != nil) {  
  12.         managedObjectContext = [[NSManagedObjectContext alloc] init];  
  13.         [managedObjectContext setPersistentStoreCoordinator: coordinator];  
  14.     }  
  15.     return managedObjectContext;  
  16. }  

這個代碼也比較簡單,不做解釋了。

 

FetchRequest(FetchRequestController)

 

這里重點講FetchRequestController,其實用戶打交道最多的就是這個控制器了。要講的東西很多,放到下面一篇吧。

這篇文章重點講講CoreData的Fetched Results Controller。

             對應(yīng)的objc類為NSFetchedResultsController。這個類是用來管理CoreData Fetch request返回的對象的。

             在創(chuàng)建這個控制器之前,必須先創(chuàng)建fetch request。 fetch request描述了詳細(xì)的查詢規(guī)則,還可以添加查詢結(jié)果的排序描述(sort descriptor)。fetchResultsController根據(jù)已經(jīng)創(chuàng)建完的fetch request來創(chuàng)建, 它是NSFetchedResultsController的實例,這個實例的主要任務(wù)就是使用fetch request來保證它所關(guān)聯(lián)的數(shù)據(jù)的新鮮性。創(chuàng)建了fetchResultsController實例后要做一下初始化,一般初始化是向這個控制器發(fā)送PerformFetch消息,下面是這一過程的代碼。

  1. - (NSFetchedResultsController *)fetchedResultsController {    
  2.     if (fetchedResultsController != nil) {    
  3.         return fetchedResultsController;    
  4.     }    
  5.     /*  
  6.     Set up the fetched results controller.  
  7.     */    
  8.     // Create the fetch request for the entity.    
  9.     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];    
  10.     // Edit the entity name as appropriate.    
  11.     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event"    
  12.     inManagedObjectContext:managedObjectContext];    
  13.     [fetchRequest setEntity:entity];    
  14.     // Set the batch size to a suitable number.    
  15.     [fetchRequest setFetchBatchSize:20];    
  16.     // Edit the sort key as appropriate.    
  17.     NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]    
  18.     initWithKey:@"timeStamp" ascending:NO];    
  19.     NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor,nil];    
  20.     [fetchRequest setSortDescriptors:sortDescriptors];    
  21.     // Edit the section name key path and cache name if appropriate.    
  22.     // nil for section name key path means "no sections".    
  23.     NSFetchedResultsController *aFetchedResultsController =    
  24.     [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest    
  25.     managedObjectContext:managedObjectContext sectionNameKeyPath:nil    
  26.     cacheName:@"Root"];    
  27.     aFetchedResultsController.delegate = self;    
  28.     self.fetchedResultsController = aFetchedResultsController;    
  29.     [aFetchedResultsController release];    
  30.     [fetchRequest release];    
  31.     [sortDescriptor release];    
  32.     [sortDescriptors release];    
  33.     return fetchedResultsController;    
  34. }    

            `這個函數(shù)用來創(chuàng)建FetchedResultsController,過程還是比較簡單的,下面是初始化這個控制器代碼。

  1. NSError *error = nil;    
  2. if(![[self  fetchedResultsController]performFetch: &error]){    
  3.     //handle the error appropriately    
  4.     NSLog(@"Unresolved error %@, %@", error, [error userInfo]);    
  5.     exit(-1);    
  6. }    

          這段代碼一般會放在viewDidLoad函數(shù)中,初始化之后,fetchedResultsController就與數(shù)據(jù)相連接了,之后要取數(shù)據(jù)都能直接從這個控制器提供的方法中去取。

            實現(xiàn)這個控制器,最關(guān)鍵的還要實現(xiàn)Fetched Results Controller Delegate Methods??刂破髋c數(shù)據(jù)源連接后,控制器監(jiān)視器會時刻監(jiān)視著數(shù)據(jù)源,當(dāng)數(shù)據(jù)源發(fā)生

改變后,監(jiān)視器會調(diào)用對應(yīng)的協(xié)議方法,改協(xié)議總共要實現(xiàn)四個方法,分別為:

  1. - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller;    
  2. - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller;    
  3. - (void)controller:(NSFetchedResultsController *)controller    
  4.    didChangeObject:(id)anObject    
  5.        atIndexPath:(NSIndexPath *)indexPath    
  6.      forChangeType:(NSFetchedResultsChangeType)type    
  7.       newIndexPath:(NSIndexPath *)newIndexPath;    
  8. - (void)controller:(NSFetchedResultsController *)controller    
  9.   didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo    
  10.            atIndex:(NSUInteger)sectionIndex    
  11.      forChangeType:(NSFetchedResultsChangeType)type;    

 

              下面依次來解釋這四個協(xié)議方法。

              1.  - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller

            當(dāng)控制器監(jiān)控的數(shù)據(jù)發(fā)生改變時,如對象被刪除,有插入,更新等,監(jiān)視器會在數(shù)據(jù)發(fā)生改變前意識到這個情況,此時就會調(diào)用這個函數(shù)。往往我們用列表的形式

表現(xiàn)數(shù)據(jù),此時意味著屏幕上的數(shù)據(jù)即將過時,因為數(shù)據(jù)馬上要改變了,這是這個協(xié)議方法的工作就是通知列表數(shù)據(jù)馬上要更新的消息,往往代碼是這樣實現(xiàn)的。 
  1. - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {    
  2.     [self.tableView beginUpdates];    
  3. }   

 

           2. - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller

            當(dāng)fetchedResultsController完成對數(shù)據(jù)的改變時,監(jiān)視器會調(diào)用這個協(xié)議方法。在上面提到的情況,這個方法要通知列表數(shù)據(jù)已經(jīng)完成,可以更新顯示的數(shù)據(jù)這個

消息,因此通常的實現(xiàn)是這樣的。

 

  1. - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {    
  2.     [self.tableView endUpdates];    
  3. }    
  3. - (void)controller:(NSFetchedResultsController *)controller

 

 

              didChangeObject:(id)anObject 

                        atIndexPath:(NSIndexPath *)indexPath 

                  forChangeType:(NSFetchedResultsChangeType)type 

                    newIndexPath:(NSIndexPath *)newIndexPath

               當(dāng)fetchedResultsController發(fā)現(xiàn)指定的對象有改變時,監(jiān)視器會調(diào)用這個協(xié)議方法。這里改變的類型從列表中體現(xiàn)有 更新、插入、刪除或者行的移動。因此這個

方法要實現(xiàn)所有的這些方法,以應(yīng)對任何一種改變。下面是這個方法的標(biāo)準(zhǔn)實現(xiàn)。

  1. - (void)controller:(NSFetchedResultsController *)controller    
  2.    didChangeObject:(id)anObject    
  3.        atIndexPath:(NSIndexPath *)indexPath    
  4.      forChangeType:(NSFetchedResultsChangeType)type    
  5.       newIndexPath:(NSIndexPath *)newIndexPath {    
  6.     switch(type) {    
  7.         case NSFetchedResultsChangeInsert:    
  8.             [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]     
  9.                             withRowAnimation:UITableViewRowAnimationFade];    
  10.             break;    
  11.         case NSFetchedResultsChangeDelete:    
  12.             [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]    
  13.                             withRowAnimation:UITableViewRowAnimationFade];    
  14.             break;    
  15.         case NSFetchedResultsChangeUpdate: {    
  16.             NSString *sectionKeyPath = [controller sectionNameKeyPath];    
  17.             if (sectionKeyPath == nil)    
  18.                 break;    
  19.             NSManagedObject *changedObject = [controller objectAtIndexPath:indexPath];    
  20.             NSArray *keyParts = [sectionKeyPath componentsSeparatedByString:@"."];    
  21.             id currentKeyValue = [changedObject valueForKeyPath:sectionKeyPath];    
  22.             for (int i = 0; i < [keyParts count] - 1; i++) {    
  23.                 NSString *onePart = [keyParts objectAtIndex:i];    
  24.                 changedObject = [changedObject valueForKey:onePart];    
  25.             }    
  26.             sectionKeyPath = [keyParts lastObject];    
  27.             NSDictionary *committedValues = [changedObject committedValuesForKeys:nil];    
  28.             if ([[committedValues valueForKeyPath:sectionKeyPath]isEqual:currentKeyValue])    
  29.                 break;    
  30.             NSUInteger tableSectionCount = [self.tableView numberOfSections];    
  31.             NSUInteger frcSectionCount = [[controller sections] count];    
  32.             if (tableSectionCount != frcSectionCount) {    
  33.                 // Need to insert a section    
  34.                 NSArray *sections = controller.sections;    
  35.                 NSInteger newSectionLocation = -1;    
  36.                 for (id oneSection in sections) {    
  37.                     NSString *sectionName = [oneSection name];    
  38.                     if ([currentKeyValue isEqual:sectionName]) {    
  39.                         newSectionLocation = [sections indexOfObject:oneSection];    
  40.                         break;    
  41.                     }    
  42.                 }    
  43.                 if (newSectionLocation == -1)    
  44.                     return; // uh oh    
  45.                 if (!((newSectionLocation == 0) && (tableSectionCount == 1)    
  46.                        && ([self.tableView numberOfRowsInSection:0] == 0)))    
  47.                     [self.tableView insertSections:[NSIndexSet indexSetWithIndex:newSectionLocation]    
  48.                                   withRowAnimation:UITableViewRowAnimationFade];    
  49.                 NSUInteger indices[2] = {newSectionLocation, 0};    
  50.                 newIndexPath = [[[NSIndexPath alloc] initWithIndexes:indiceslength:2] autorelease];    
  51.             }    
  52.         }    
  53.         case NSFetchedResultsChangeMove    
  54.             if (newIndexPath != nil) {    
  55.                 [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]    
  56.                                       withRowAnimation:UITableViewRowAnimationFade];    
  57.                 [self.tableView insertRowsAtIndexPaths: [NSArray arrayWithObject:newIndexPath]    
  58.                                       withRowAnimation: UITableViewRowAnimationRight];    
  59.             }    
  60.             else {    
  61.                 [self.tableView reloadSections:[NSIndexSet    
  62.                 indexSetWithIndex:[indexPath section]]withRowAnimation:UITableViewRowAnimationFade];    
  63.             }    
  64.             break;    
  65.         default:    
  66.             break;    
  67.     }    
  68. }    

 

 

          從上面的代碼可以看出,插入,刪除,移動是比較簡單的,最復(fù)雜的是更新。這個代碼是xcode的模板代碼,基本能適用我們遇到的情況,對更新里面的代碼我還不是非常確定,所以這里留著等過幾天完全吃透了再補(bǔ)上。

 

 

           4. - (void)controller:(NSFetchedResultsController *)controller

            didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo

                                atIndex:(NSUInteger)sectionIndex 

                 forChangeType:(NSFetchedResultsChangeType)type

              當(dāng)改變控制器管理的對象后引起了列表section的變化,此時監(jiān)視器就會調(diào)用這個協(xié)議函數(shù)。

            下面是標(biāo)準(zhǔn)實現(xiàn)。 

  1. - (void)controller:(NSFetchedResultsController *)controller    
  2.   didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo    
  3.            atIndex:(NSUInteger)sectionIndex    
  4.      forChangeType:(NSFetchedResultsChangeType)type {    
  5.     switch(type) {    
  6.         case NSFetchedResultsChangeInsert:    
  7.             if (!((sectionIndex == 0) && ([self.tableView numberOfSections] == 1)    
  8.                              && ([self.tableView numberOfRowsInSection:0] == 0)))    
  9.                 [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]    
  10.                               withRowAnimation:UITableViewRowAnimationFade];    
  11.             break;    
  12.         case NSFetchedResultsChangeDelete:    
  13.             if (!((sectionIndex == 0) && ([self.tableView numberOfSections] == 1)    
  14.                              && ([self.tableView numberOfRowsInSection:0] == 0)))    
  15.                 [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]    
  16.                               withRowAnimation:UITableViewRowAnimationFade];    
  17.             break;    
  18.         case NSFetchedResultsChangeMove:    
  19.         case NSFetchedResultsChangeUpdate:    
  20.         default:    
  21.             break;    
  22.     }    
  23. }    

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多