生活随笔
收集整理的這篇文章主要介紹了
[Cocoa]深入浅出 Cocoa 之 Core Data(2)- 手动编写代码
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
深入淺出 Cocoa 之 Core Data(2)- 代碼示例
羅朝輝(http://blog.csdn.net/kesalin)
CC 許可,轉(zhuǎn)載請(qǐng)注明出處
前面
詳細(xì)講解了 Core Data 的框架以及設(shè)計(jì)的類,下面我們來講解一個(gè)完全手動(dòng)編寫代碼使用這些類的示例,這個(gè)例子來自蘋果官方示例。在這個(gè)例子里面,我們打算做這樣一件事情:記錄程序運(yùn)行記錄(時(shí)間與 process id),并保存到xml文件中。我們使用 Core Data 來做這個(gè)事情。
示例代碼下載:點(diǎn)擊這里
一,建立一個(gè)新的 Mac?command-line tool application 工程,命名為 CoreDataTutorial。為支持垃圾主動(dòng)回收機(jī)制,點(diǎn)擊項(xiàng)目名稱,在右邊的 Build Setting 中查找?garbage 關(guān)鍵字,將找到的 Objective-C Garbage Collection 設(shè)置為 Required [-fobj-gc-only]。并將 ?main.m 中 的 main() 方法修改為如下:
[cpp] ?view plaincopyprint?
int ?main?( int ?argc,? const ? char ?*?argv[])?? {?? ????NSLog(@"?===?Core?Data?Tutorial?===" );?? ?? ?????? ?????? ????objc_startCollectorThread();?? ?????? ????return ?0;?? }??
二,創(chuàng)建并設(shè)置模型類
在 main() 之前添加如下方法:
[cpp] ?view plaincopyprint?
NSManagedObjectModel?*managedObjectModel()?? {?? ????static ?NSManagedObjectModel?*moModel?=?nil;?? ?? ????if ?(moModel?!=?nil)?{?? ????????return ?moModel;?? ????}?? ?????? ????moModel?=?[[NSManagedObjectModel?alloc]?init];?? ?????? ?????? ?????? ????NSEntityDescription?*runEntity?=?[[NSEntityDescription?alloc]?init];?? ????[runEntity?setName:@"Run" ];?? ????[runEntity?setManagedObjectClassName:@"Run" ];?? ?????? ????[moModel?setEntities:[NSArray?arrayWithObject:runEntity]];?? ?????? ?????? ?????? ????NSAttributeDescription?*dateAttribute?=?[[NSAttributeDescription?alloc]?init];?? ????[dateAttribute?setName:@"date" ];?? ????[dateAttribute?setAttributeType:NSDateAttributeType];?? ????[dateAttribute?setOptional:NO];?? ?????? ????NSAttributeDescription?*idAttribute?=?[[NSAttributeDescription?alloc]?init];?? ????[idAttribute?setName:@"processID" ];?? ????[idAttribute?setAttributeType:NSInteger32AttributeType];?? ????[idAttribute?setOptional:NO];?? ????[idAttribute?setDefaultValue:[NSNumber?numberWithInteger:-1]];?? ?? ?????? ?????? ?????? ????NSExpression?*lhs?=?[NSExpression?expressionForEvaluatedObject];?? ????NSExpression?*rhs?=?[NSExpression?expressionForConstantValue:[NSNumber?numberWithInteger:0]];?? ?????? ????NSPredicate?*validationPredicate?=?[NSComparisonPredicate?? ????????????????????????????????????????predicateWithLeftExpression:lhs?? ????????????????????????????????????????rightExpression:rhs?? ????????????????????????????????????????modifier:NSDirectPredicateModifier?? ????????????????????????????????????????type:NSGreaterThanPredicateOperatorType?? ????????????????????????????????????????options:0];?? ?????? ????NSString?*validationWarning?=?@"Process?ID?<?1" ;?? ????[idAttribute?setValidationPredicates:[NSArray?arrayWithObject:validationPredicate]?? ??????????????????withValidationWarnings:[NSArray?arrayWithObject:validationWarning]];?? ?????? ?????? ?????? ????NSArray?*properties?=?[NSArray?arrayWithObjects:?dateAttribute,?idAttribute,?nil];?? ????[runEntity?setProperties:properties];?? ?????? ?????? ?????? ????NSMutableDictionary?*localizationDictionary?=?[NSMutableDictionary?dictionary];?? ????[localizationDictionary?setObject:@"Date" ?forKey:@ "Property/date/Entity/Run" ];?? ????[localizationDictionary?setObject:@"Process?ID" ?forKey:@ "Property/processID/Entity/Run" ];?? ????[localizationDictionary?setObject:@"Process?ID?must?not?be?less?than?1" ?forKey:@ "ErrorString/Process?ID?<?1" ];?? ?????? ????[moModel?setLocalizationDictionary:localizationDictionary];?? ?????? ????return ?moModel;?? }??
在上面的代碼中:
1)我們創(chuàng)建了一個(gè)全局模型?moModel; 2)并在其中創(chuàng)建一個(gè)名為?Run 的 Entity,這個(gè) Entity 對(duì)應(yīng)的?ManagedObject 類名為?Run(很快我們將創(chuàng)建這樣一個(gè)類); 3)給 Run Entity 添加了兩個(gè)必須的 Property:date 和 processID,分別表示運(yùn)行時(shí)間以及進(jìn)程 ID;并設(shè)置默認(rèn)的進(jìn)程 ID 為 -1; 4)給 processID 特性設(shè)置檢驗(yàn)條件:必須大于 0; 5)給模型設(shè)置本地化描述詞典;
本地化描述提供對(duì) Entity,Property,Error信息等的便于理解的描述,其可用的鍵值對(duì)如下表:
Key
Value
"Entity/NonLocalizedEntityName"
"LocalizedEntityName"
"Property/NonLocalizedPropertyName/Entity/EntityName"
"LocalizedPropertyName"
"Property/NonLocalizedPropertyName"
"LocalizedPropertyName"
"ErrorString/NonLocalizedErrorString"
"LocalizedErrorString"
三,創(chuàng)建并設(shè)置運(yùn)行時(shí)類和對(duì)象
由于要用到存儲(chǔ)功能,所以我們必須定義持久化數(shù)據(jù)的存儲(chǔ)路徑。我們?cè)?main() 之前添加如下方法設(shè)置存儲(chǔ)路徑:
[cpp] ?view plaincopyprint?
NSURL?*applicationLogDirectory()?? {?? ????NSString?*LOG_DIRECTORY?=?@"CoreDataTutorial" ;?? ????static ?NSURL?*ald?=?nil;?? ?????? ????if ?(ald?==?nil)?? ????{?? ????????NSFileManager?*fileManager?=?[[NSFileManager?alloc]?init];?? ????????NSError?*error?=?nil;?? ????????NSURL?*libraryURL?=?[fileManager?URLForDirectory:NSLibraryDirectory?inDomain:NSUserDomainMask?? ???????????????????????????????????????appropriateForURL:nil?create:YES?error:&error];?? ????????if ?(libraryURL?==?nil)?{?? ????????????NSLog(@"Could?not?access?Library?directory\n%@" ,?[error?localizedDescription]);?? ????????}?? ????????else ?? ????????{?? ????????????ald?=?[libraryURL?URLByAppendingPathComponent:@"Logs" ];?? ????????????ald?=?[ald?URLByAppendingPathComponent:LOG_DIRECTORY];?? ?????????????? ????????????NSLog(@"?>>?log?path?%@" ,?[ald?path]);?? ?????????????? ????????????NSDictionary?*properties?=?[ald?resourceValuesForKeys:[NSArray?arrayWithObject:NSURLIsDirectoryKey]?error:&error];?? ????????????if ?(properties?==?nil)?? ????????????{?? ????????????????if ?(![fileManager?createDirectoryAtPath:[ald?path]?withIntermediateDirectories:YES?attributes:nil?error:&error])?? ????????????????{?? ????????????????????NSLog(@"Could?not?create?directory?%@\n%@" ,?? ??????????????????????????[ald?path],?[error?localizedDescription]);?? ????????????????????ald?=?nil;?? ????????????????}?? ????????????}?? ????????}?? ????}?? ?????? ????return ?ald;?? }??
在上面的代碼中,我們將持久化數(shù)據(jù)文件保存到路徑:
/Users/kesalin/Library/Logs/CoreDataTutorial 下。
下面,我們來創(chuàng)建運(yùn)行時(shí)對(duì)象:ManagedObjectContext 和 PersistentStoreCoordinator。
[cpp] ?view plaincopyprint?
NSManagedObjectContext?*managedObjectContext()?? {?? ????static ?NSManagedObjectContext?*moContext?=?nil;?? ????if ?(moContext?!=?nil)?{?? ????????return ?moContext;?? ????}?? ?????? ????moContext?=?[[NSManagedObjectContext?alloc]?init];?? ?????? ?????? ?????? ????NSManagedObjectModel?*moModel?=?managedObjectModel();?? ????NSPersistentStoreCoordinator?*coordinator?=?[[NSPersistentStoreCoordinator?alloc]?initWithManagedObjectModel:moModel];?? ????[moContext?setPersistentStoreCoordinator:?coordinator];?? ?????? ?????? ?????? ????NSString?*STORE_TYPE?=?NSXMLStoreType;?? ????NSString?*STORE_FILENAME?=?@"CoreDataTutorial.xml" ;?? ?????? ????NSError?*error?=?nil;?? ????NSURL?*url?=?[applicationLogDirectory()?URLByAppendingPathComponent:STORE_FILENAME];?? ?????? ????NSPersistentStore?*newStore?=?[coordinator?addPersistentStoreWithType:STORE_TYPE?? ????????????????????????????????????????????????????????????configuration:nil?? ??????????????????????????????????????????????????????????????????????URL:url?? ??????????????????????????????????????????????????????????????????options:nil?? ????????????????????????????????????????????????????????????????????error:&error];?? ?????? ????if ?(newStore?==?nil)?{?? ????????NSLog(@"Store?Configuration?Failure\n%@" ,?([error?localizedDescription]?!=?nil)???[error?localizedDescription]?:?@ "Unknown?Error" );?? ????}?? ?? ????return ?moContext;?? }??
在上面的代碼中:
1)我們創(chuàng)建了一個(gè)全局?ManagedObjectContext 對(duì)象?moContext;
2)并在設(shè)置其 persistent store coordinator,存儲(chǔ)類型為 xml,保存文件名為:CoreDataTutorial.xml,并將其放到前面定義的存儲(chǔ)路徑下。
好,至此萬事具備,只欠 ManagedObject 了!下面我們就來定義這個(gè)數(shù)據(jù)對(duì)象類。向工程添加 Core Data->NSManagedObject subclass 的類,名為 Run (模型中 Entity 定義的類名)?。
Run.h
[cpp] ?view plaincopyprint?
#import?<CoreData/NSManagedObject.h> ?? ?? @interface?Run?:?NSManagedObject?? {?? ????NSInteger?processID;?? }?? ?? @property?(retain)?NSDate?*date;?? @property?(retain)?NSDate?*primitiveDate;?? @property?NSInteger?processID;?? ?? @end??
Run.m
[cpp] ?view plaincopyprint?
?? ?? ?? ?? ?? ?? ?? ?? #import?"Run.h" ?? ?? @implementation?Run?? ?? @dynamic?date;?? @dynamic?primitiveDate;?? ?? -?(void )?awakeFromInsert?? {?? ????[super?awakeFromInsert];?? ?? ????self.primitiveDate?=?[NSDate?date];?? }?? ?? #pragma?mark?- ?? #pragma?mark?Getter?and?setter ?? ?? -?(NSInteger)processID??? {?? ????[self?willAccessValueForKey:@"processID" ];?? ????NSInteger?pid?=?processID;?? ????[self?didAccessValueForKey:@"processID" ];?? ????return ?pid;?? }?? ?? -?(void )setProcessID:(NSInteger)newProcessID?? {?? ????[self?willChangeValueForKey:@"processID" ];?? ????processID?=?newProcessID;?? ????[self?didChangeValueForKey:@"processID" ];?? }?? ?? ?? ?? -?(void )setNilValueForKey:(NSString?*)key?{?? ?????? ????if ?([key?isEqualToString:@ "processID" ])?{?? ????????self.processID?=?0;?? ????}?? ????else ?{?? ????????[super?setNilValueForKey:key];?? ????}?? }?? ?? @end??
注意:
1)這個(gè)類中的 date 和?primitiveDate 的訪問屬性為?@dynamic,這表明在運(yùn)行期會(huì)動(dòng)態(tài)生成對(duì)應(yīng)的 setter 和 getter;
2)在這里我們演示了如何正確地手動(dòng)實(shí)現(xiàn) processID 的 setter 和 getter:為了讓 ManagedObjecContext ?能夠檢測(cè) processID的變化,以及自動(dòng)支持 undo/redo,我們需要在訪問和更改數(shù)據(jù)對(duì)象時(shí)告之系統(tǒng),will/didAccessValueForKey 以及?will/didChangeValueForKey 就是起這個(gè)作用的。
3)當(dāng)我們?cè)O(shè)置 nil 給數(shù)據(jù)對(duì)象 processID?時(shí),我們可以在 setNilValueForKey?捕獲這個(gè)情況,并將 processID ?置 0;
4)當(dāng)數(shù)據(jù)對(duì)象被插入到 ManagedObjectContext 時(shí),我們?cè)?awakeFromInsert?將時(shí)間設(shè)置為當(dāng)前時(shí)間。
三,創(chuàng)建或讀取數(shù)據(jù)對(duì)象,設(shè)置其值,保存 好,至此真正的萬事具備,我們可以創(chuàng)建或從持久化文件中讀取數(shù)據(jù)對(duì)象,設(shè)置其值,并將其保存到持久化文件中。本例中持久化文件為 xml 文件。修改 main() 中代碼如下:
[cpp] ?view plaincopyprint?
int ?main?( int ?argc,? const ? char ?*?argv[])?? {?? ????NSLog(@"?===?Core?Data?Tutorial?===" );?? ?? ?????? ?????? ????objc_startCollectorThread();?? ?? ????NSError?*error?=?nil;?? ?????? ????NSManagedObjectModel?*moModel?=?managedObjectModel();?? ????NSLog(@"The?managed?object?model?is?defined?as?follows:\n%@" ,?moModel);?? ?????? ????if ?(applicationLogDirectory()?==?nil)?{?? ????????exit(1);?? ????}?? ?????? ????NSManagedObjectContext?*moContext?=?managedObjectContext();?? ?????? ?????? ?????? ????NSEntityDescription?*runEntity?=?[[moModel?entitiesByName]?objectForKey:@"Run" ];?? ????Run?*run?=?[[Run?alloc]?initWithEntity:runEntity?insertIntoManagedObjectContext:moContext];?? ????NSProcessInfo?*processInfo?=?[NSProcessInfo?processInfo];?? ????run.processID?=?[processInfo?processIdentifier];?? ?????? ????if ?(![moContext?save:?&error])?{?? ????????NSLog(@"Error?while?saving\n%@" ,?([error?localizedDescription]?!=?nil)???[error?localizedDescription]?:?@ "Unknown?Error" );?? ????????exit(1);?? ????}?? ?????? ?????? ?????? ????NSFetchRequest?*request?=?[[NSFetchRequest?alloc]?init];?? ????[request?setEntity:runEntity];?? ?? ????NSSortDescriptor?*sortDescriptor?=?[[NSSortDescriptor?alloc]?initWithKey:@"date" ?ascending:YES];?? ????[request?setSortDescriptors:[NSArray?arrayWithObject:sortDescriptor]];?? ?????? ????error?=?nil;?? ????NSArray?*array?=?[moContext?executeFetchRequest:request?error:&error];?? ????if ?((error?!=?nil)?||?(array?==?nil))?? ????{?? ????????NSLog(@"Error?while?fetching\n%@" ,?([error?localizedDescription]?!=?nil)???[error?localizedDescription]?:?@ "Unknown?Error" );?? ????????exit(1);?? ????}?? ?????? ?????? ?????? ????NSDateFormatter?*formatter?=?[[NSDateFormatter?alloc]?init];?? ????[formatter?setDateStyle:NSDateFormatterMediumStyle];?? ????[formatter?setTimeStyle:NSDateFormatterMediumStyle];?? ?????? ????NSLog(@"%@?run?history:" ,?[processInfo?processName]);?? ?????? ????for ?(run?in?array)?? ????{?? ????????NSLog(@"On?%@?as?process?ID?%ld" ,?[formatter?stringForObjectValue:run.date],?run.processID);?? ????}?? ?????? ????return ?0;?? }??
在上面的代碼中:
1)我們先獲得全局的?NSManagedObjectModel 和?NSManagedObjectContext 對(duì)象:moModel 和?moContext;
2)并創(chuàng)建一個(gè)Run Entity,設(shè)置其 Property?processID 為當(dāng)前進(jìn)程的 ID;
3)將該數(shù)據(jù)對(duì)象保存到持久化文件中:[moContext?
save
: &error]。我們無需與?PersistentStoreCoordinator 打交道,只需要給 ManagedObjectContext 發(fā)送 save 消息即可,NSManagedObjectContext 會(huì)透明地在后面處理對(duì)持久化數(shù)據(jù)文件的讀寫;
4)然后我們創(chuàng)建一個(gè)?FetchRequest 來查詢持久化數(shù)據(jù)文件中保存的數(shù)據(jù)記錄,并將結(jié)果按照日期升序排列。查詢操作也是由 ManagedObjectContext?來處理的:[moContext?
executeFetchRequest
:request?
error
:&error];
5)將查詢結(jié)果打印輸出;
大功告成!編譯運(yùn)行,我們可以得到如下顯示:
[cpp] ?view plaincopyprint?
2011-09-03?21:42:47.556?CoreDataTutorial[992:903]?CoreDataTutorial?run?history:?? 2011-09-03?21:42:47.557?CoreDataTutorial[992:903]?On?2011-9-3?下午09:41:56?as?process?ID?940?? 2011-09-03?21:42:47.557?CoreDataTutorial[992:903]?On?2011-9-3?下午09:42:16?as?process?ID?955?? 2011-09-03?21:42:47.558?CoreDataTutorial[992:903]?On?2011-9-3?下午09:42:20?as?process?ID?965?? 2011-09-03?21:42:47.558?CoreDataTutorial[992:903]?On?2011-9-3?下午09:42:24?as?process?ID?978?? 2011-09-03?21:42:47.559?CoreDataTutorial[992:903]?On?2011-9-3?下午09:42:47?as?process?ID?992??
通過這個(gè)例子,我們可以更好理解 Core Data ?的運(yùn)作機(jī)制。在?Core Data 中我們最常用的就是?ManagedObjectContext,它幾乎參與對(duì)數(shù)據(jù)對(duì)象的所有操作,包括對(duì) undo/redo 的支持;而 Entity 對(duì)應(yīng)的運(yùn)行時(shí)類為?ManagedObject,我們可以理解為抽象數(shù)據(jù)結(jié)構(gòu)?Entity?在內(nèi)存中由 ManagedObject 來體現(xiàn),而 Perproty 數(shù)據(jù)類型在內(nèi)存中則由?ManagedObject 類的成員屬性來體現(xiàn)。一般我們不需要與?PersistentStoreCoordinator 打交道,對(duì)數(shù)據(jù)文件的讀寫操作都由?ManagedObjectContext 為我們代勞了。
總結(jié)
以上是生活随笔 為你收集整理的[Cocoa]深入浅出 Cocoa 之 Core Data(2)- 手动编写代码 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。