iPhone 數據庫使用
CoreData
介紹
在Cocoa環境下,如果你想使用數據庫(如sqlite),你可以使用sql語句的方式通過相關的工具類進行數據庫的直接操作。當然你也可以通過別人封裝之后的一些簡單框架,使得你的操作更加簡單(如FMDB BNRPersistence)。
Cocoa框架本身提供了CoreData這個API可方便的讓開發者通過操作對象的方式在操作數據庫。CoreData是一個對象圖 (object graph)以及持久化的管理框架。我們可以通過CoreData創對象,設置好象之間的關系,然后將其持久化(我們甚至可以使用內存數據庫),或者從硬 盤上將持久化后的數據加載到內存中。對象圖,我們可以創建一個個的對象,并維持不同對象之間的關系,一對一,一對多等。
CoreData有大量的特性,諸如支持Redo,Undo的功能,這些很多Document based的程序中顯得非常的有用。提供數據model結構變化輕量級的遷移方案。CoreData還通過Binding特性和控件的緊密結合,這樣使得 只需要少量的代碼便可以完成強大的功能,下面是一個例子
http://www.timisted.net/blog/archive/multiple-windows-with-core-data/
存儲方式
Core Data可以將數據存儲為XML,二進制文件或SQLite文件。在Mac OS X 10.5 Leopard及以后的版本中,開發者也可以通過繼承NSPersistentStore類以創建自定義的存儲格式。每種方法都有其優缺點,例如XML的 可讀性,SQLite的節約空間等。
Core Data的這一方面類似于原始的Enterprise Objects Framework(EOF)系統,但EOF中開發者可以使用相對簡潔的查詢方式,而在Core Data中,只能使用一個語法類似SQL子集的查詢語言,稱為Predicate。Core Data是標準化的,可以自由的讀寫Xcode數據模型文件(通常是.xcdatamodel文件)。
與EOF不同,Core Data目前沒有設計多用戶或多線程訪問模式。模型遷移通常也需要代碼,若其它開發者依賴于某個數據模型,則該數據模型的設計者可能在模型發生改變時需要與新數據模型一起提供版本轉換代碼。
操作簡介
Core Data由相對龐大的類繼承體系組成,但開發者需要關注的接口只是其中的一個相對小的子集。
一般需要定義以下Core Data的三個必備
NSPersistentStoreCoordinator *persistentStoreCoordinator;
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;
以及使用時需要用到的
NSFetchedResultsController *fetchedResultsController;
具體的使用例子比較多,后面介紹一下在使用過程中遇到的一些問題。或許可以幫到你。
分享
1. 使用Table時在3.0版本時會Crash
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
return [sectionInfo numberOfObjects];
}
3.0版本的時候如果你在numberOfRowsInSection的回調時Crash,那么加上下面這個回調就沒事了,這樣在無數據的時候數組就不會越界了。Apple在3.0才第一次上CoreData,總有不小心的時候,后面的版本就處理得很好。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [[self.fetchedResultsController sections] count];
}
2. 又Crash了,檢查一下,記得在所有增刪改查前已經調用過下面這幾句話,并且在重置fetchedResultsController 的時候也要重新調用,所以我把它寫到創建的尾部了。
NSError *error;
if (![fetchedResultsController performFetch:&error])
NSLog(@"Error performing fetch: %@", [error localizedDescription]);
3. 錯誤信息看不懂,用
- (void) handleError:(NSError *)error fromSource:(NSString *)sourceString
{
NDLOG(@"Unresolved error %@ at %@, %@", error, sourceString, [error userInfo]);
[DataController dumpError:error];
}
打出來的確實不是很清楚。有時候還是不準確不完整的信息。換一個吧,我們自己來。
+ (void) dumpError:(NSError *) error {
NDLOG(@"Failed to save to data store: %@", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0) {
for(NSError* detailedError in detailedErrors) {
NDLOG(@" DetailedError: %@", [detailedError userInfo]);
}
}
else {
NDLOG(@" %@", [error userInfo]);
}
}
4. 不是每次都要fetchedResultsController的,有時候直接用NSFetchRequest更方便。
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *tagEntity = [NSEntityDescription entityForName:@"entityName" inManagedObjectContext:managedObjectContext];
[request setEntity:tagEntity];
NSError *error = nil;
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
return [array count];
5. 有時候沒SQL命令確實效率不怎么樣。為了做一個更新數據庫的操作,瞧這代碼,幸虧N都是很小的值。
NSMutableArray* persistent = [NSMutableArray arrayWithArray:local];
NSMutableArray* netData = [NSMutableArray arrayWithArray:netReturn];
for(id info in persistent) {
BOOL found = NO;
for(id data in netData) {
if(找到) {
更新對象數據等操作
[netData removeObject: data];
found = YES;
break;
}
}
if(!found) {
移除不必要的數據等
}
}
for(id data in netData) {
插入新增等操作
}
最后是保存等操作
}
6. 在使用的過程中,其功能強大省去了很多的事情,但是其實有很多需要注意的東西嗎,delegate的處理等等。在改變模型的 時候如果沒有更新方案的話會很麻煩的。效率上也是值得商榷,還有一堆高度重復的代碼也是看起來不舒服的地方。還有就是感覺數據源非常適合使用Table來 處理。
7. 在上面的第五點的更新操作為什么需要這樣子麻煩呢,因為需要避免用戶在操作一個數據庫中一個已經被刪除的但是已經載到內存中 對象。但是這種情況并沒有能夠完全規避,這時候在訪問對象數據前,需要及時的判斷這個內存中的對象還有效嗎。調用對象的 isFault(NSManagedObject),進行判斷,及時避免不必要的操作和崩潰。
本文來自http://blog.csdn.net/arthurchenjs/article/details/6339659