IOS高階程式設計之二:IOS的資料儲存與IO

橙子瓣發表於2015-05-05

一、應用程式沙盒

     IOS應用程式職能在系統為該應用所分配的檔案區域下讀寫檔案,這個檔案區域就是應用程式沙盒。所有的非程式碼檔案如:圖片、聲音、映象等等都存放在此。

在mac中command+shift+G命令,然後輸入users/使用者名稱/library命令進入庫,然後依次進入application support/iphone simulator/版本/applications資料夾,這裡面的各個資料夾對應著各個應用程式。

Documents:除了基於NSUserDefaults的首選項設定外,應用程式的資料、檔案都儲存在該目錄下

Library:基於NSUserDefaults的首選項引數儲存在Library/Preferences下

tmp:應用程式儲存臨時檔案,ios同步時itunes不會同步這裡面的資料,當應用程式不在需要這些檔案時,應當刪除以避免佔用空間。

獲取documents路徑:

1 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
2 NSString *dd = [paths objectAtIndex:0];

獲取tmp目錄:

1 NSString *tempPath = NSTemporaryDirectory();

那麼我們在儲存資料時使用哪種髮式比較好呢,這個當然還要具體情況具體對待。
當儲存小資料量的資料時,可以使用NSArray或者NSDictionary,呼叫writeToFile:atomically:方法寫入一個檔案,使用時讀取檔案內容即可。

當儲存大資料量的資料時,可以選擇使用sqllite,ios提供了CoreData框架。

 

二、應用程式引數與使用者預設設定

1、使用Settings Bundle

Settings Bundle時應用程式中的一組特殊檔案,用於儲存較簡單的各種配置資訊。如果使用了Settings Bundle,ios自帶的設定應用則會顯示你的app

2、使用NSUserDefaults讀取、儲存應用程式引數

NSUserDefaults是一個單例類,每個應用程式只有一個NSUserDefaults物件,Settings Bundle設定的引數,也可以通過NSUserDefaults來讀取和設定

獲取NSUserDefaults的方法:

1 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

獲取NSUserDefaults物件後,可以獲取和設定應用程式引數

xxForKey:(NSString *) key  =>xx表示各種型別,根據key獲取值

setBool:(xxx) value forKey:(NSString *) key =>設定引數

設定完引數後,呼叫synchronize方法進行儲存。

3、屬性列表

屬性列表就是文章開始提到的利用NSArray和NSDictionary將資料寫入到檔案的儲存方法。

但是有一些限制,只有下列型別的值儲存到NSArray和NSDictionary中才可以直接呼叫writeToFile方法執行儲存:

NSArray、NSMutableArray、NSDictionary、NSMutableDictionary、NSData、NSMutableData、NSString、NSMutableString、NSValue、NSNumber

如果NSArray和NSDictionary儲存了我們自定義的類,那麼將不能直接呼叫writeToFile方法執行儲存。(可以考慮使用物件歸檔的方法進行儲存)

 1 //使用屬性列表儲存3個使用者的賬號密碼
 2     accountList = [[NSMutableArray alloc] init];
 3     [accountList addObject:[NSDictionary
 4                                 dictionaryWithObjects:[NSArray arrayWithObjects:@"loginname",@"loginpwd", nil]
 5                                 forKeys:[NSArray arrayWithObjects:@"305213781",@"123123", nil]]];
 6     [accountList addObject:[NSDictionary
 7                             dictionaryWithObjects:[NSArray arrayWithObjects:@"loginname",@"loginpwd", nil]
 8                             forKeys:[NSArray arrayWithObjects:@"475782389",@"123456", nil]]];
 9     [accountList addObject:[NSDictionary
10                             dictionaryWithObjects:[NSArray arrayWithObjects:@"loginname",@"loginpwd", nil]
11                             forKeys:[NSArray arrayWithObjects:@"330577588",@"123456789", nil]]];
12     [accountList writeToFile:[self filePath] atomically:YES];
13     
14     //使用UIActionSheet提示使用者儲存成功
15     UIActionSheet *sheet =[[UIActionSheet alloc] initWithTitle:@"儲存成功" delegate:nil cancelButtonTitle:nil destructiveButtonTitle:@"確定" otherButtonTitles:nil, nil];
16     [sheet showInView:self.view];

 

4、使用Sqlite3資料庫

1)為專案增加libsqlite3.dylib,這是一個原生的C函式庫

常用函式:

int sqlite3_close(sqlite3 *):關閉sqlite3 *所代表的資料連線,並釋放底層資料庫連線資源。在呼叫該函式之前,必須先呼叫sqlite3_finalize()函式,呼叫sqlite3_blob_close()函式關閉所有的blob處理器,否則將會返回SQLITE_BUSY

int sqlite3_exec(sqlite3*,const char *sql, int (*callback)(void*, int ,char**,char**),void *,char **errmsg):用於執行沒有返回值的sql語句

sqlite3_int64  sqlite3_last_insert_rowid(sqlite3*):返回sqlite3代表的資料庫最後一次插入行的id

int sqlite3_changes(sqlite3*):執行某條dml語句後,返回受影響行數

void sqlite3_interrupt(sqlite3*):中斷一個長時間執行的查詢語句

int sqlite3_complete(const char *sql):用於判斷sql語句是否執行完成

int sqlite3_open(const char * filename,sqlite3 ** ppdb):開啟與filename檔案的連結,並讓ppdb引數引用被開啟的資料庫連線

const char *sqlite3_sql(sqlite3_stmt *pStmt):用於提取sqlite3_stmt(預編譯SQL語句產生的結果)中包裝的sql語句

等等。。。太多了不一一列舉了

操作sqlite資料庫的大致步驟如下:

1、呼叫sqlite3_open方法開啟與資料庫的連線

2、執行語句

3、sqlite3_close函式關閉資料庫連線

 

2)使用Core Data框架

Core Data框架是一個純粹的物件導向的框架,允許開發者以物件導向的方式持久化操作SQLite資料庫。core data底層的持久化儲存方式可以是Sqlite資料庫,也可以是xml,也可以是記憶體。

Core Data的核心概念是實體,由Core Data管理的模型物件,它必須是NSManagedObject類或者它的子類的例項。

Core Data應用中的核心API有如下幾個:

託管物件模型(NSManagedObjectModel):該物件負責管理整個應用的所有實體以及實體之間的關聯關係。當開發者使用Xcode的圖形介面設計了實體與實體間的關聯關係之後,需要使用該物件來載入、管理應用的託管物件模型

持久化儲存協調器(NSPersistentStoreCoordinator):負責管理底層的儲存檔案,例如sqlite資料庫等等

託管物件上下文(NSManagedObjectContext):該物件是Core Data的核心,增刪改查都需要通過它來進行

實體描述(NSEntityDescription):關於某個實體的描述資訊

抓取請求(NSFetchRequest):該物件封裝了查詢實體的請求,包括程式需要查詢哪些實體、查詢條件、排序規則等

使用Core Data持久化的步驟大致如下

1、建立NSManagedObjectModel物件來載入管理應用對應的託管物件模型

2、以NSManagedObjectModel物件為基礎,根據實際需要建立NSPersistentStoreCoordinator物件,該物件確定底層資料的儲存形式

3、以NSManagedObjectModel物件為基礎,建立NSManagedObjectContext物件

4、對於普通的增、刪、改操作,需要分別先新建實體、刪除實體、修改實體,然後呼叫NSManagedObjectContext物件的save方法,儲存修改

5、如果執行查詢,需要先建立NSFetchRequest物件,在呼叫NSManagedObjectContext物件的executeFetchRequest:error:方法,返回所有匹配條件的實體組成的NSArray

 

使用Core Data的例子來和大家一起學習。

首先,建立一個建立一個Single View Application,下面有個Use Core Data選項,打上勾,之後Xcode已經為你做好了準備工作,開啟AppDelete.m就可以看到

 1 #pragma mark - Core Data stack
 2 
 3 @synthesize managedObjectContext = _managedObjectContext;
 4 @synthesize managedObjectModel = _managedObjectModel;
 5 @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
 6 
 7 - (NSURL *)applicationDocumentsDirectory {
 8     // The directory the application uses to store the Core Data store file. This code uses a directory named "esitech.Unit_3" in the application's documents directory.
 9     return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
10 }
11 
12 - (NSManagedObjectModel *)managedObjectModel {
13     // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
14     if (_managedObjectModel != nil) {
15         return _managedObjectModel;
16     }
17     //獲取實體模型檔案對應的nsurl
18     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Unit_3" withExtension:@"momd"];
19     _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
20     return _managedObjectModel;
21 }
22 
23 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
24     // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
25     if (_persistentStoreCoordinator != nil) {
26         return _persistentStoreCoordinator;
27     }
28     
29     // Create the coordinator and store
30     //以持久化模型為基礎,建立持久化儲存協調器物件
31     _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
32     //獲取sqlite資料庫檔案的儲存目錄
33     NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Unit_3.sqlite"];
34     NSError *error = nil;
35     NSString *failureReason = @"There was an error creating or loading the application's saved data.";
36     //設定儲存協調器採用sqlite,如果失敗列印失敗資訊
37     if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
38         // Report any error we got.
39         NSMutableDictionary *dict = [NSMutableDictionary dictionary];
40         dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
41         dict[NSLocalizedFailureReasonErrorKey] = failureReason;
42         dict[NSUnderlyingErrorKey] = error;
43         error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
44         // Replace this with code to handle the error appropriately.
45         // 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.
46         NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
47         abort();
48     }
49     
50     return _persistentStoreCoordinator;
51 }
52 
53 
54 - (NSManagedObjectContext *)managedObjectContext {
55     // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
56     if (_managedObjectContext != nil) {
57         return _managedObjectContext;
58     }
59     
60     NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
61     if (!coordinator) {
62         return nil;
63     }
64     _managedObjectContext = [[NSManagedObjectContext alloc] init];
65     //設定上下文使用的持久化型別
66     [_managedObjectContext setPersistentStoreCoordinator:coordinator];
67     return _managedObjectContext;
68 }
69 
70 #pragma mark - Core Data Saving support
71 
72 - (void)saveContext {
73     NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
74     if (managedObjectContext != nil) {
75         NSError *error = nil;
76         if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
77             // Replace this implementation with code to handle the error appropriately.
78             // 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.
79             NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
80             abort();
81         }
82     }
83 }

三個重要的物件NSManagedObjectModelNSPersistentStoreCoordinatorNSManagedObjectContext的例項已經為你設定好了,當我們要執行相關增刪改查時,直接呼叫委託類的managedObjectContext屬性操作即可。

在建立專案後,會發現專案中有一個**.xcdatamodeld檔案,點選後就會出現實體模型設計介面

 
 在剛剛的設計檢視中新增一個類:EventEntity,新增兩個屬性=》happenDate(Data)、name(string)
單擊Xcode主選單的Editor=》Create NSManagedObject Subclass選單,來建立一個子類,之後你的專案中就會建立一個類:EventEntity : NSManagedObject
 
先完成一些準備工作,獲取appdelete物件,定義一個nameCount變數記錄新增了幾個物件
 1 #import "SqliteViewController.h"
 2 #import "EventEntity.h"
 3 #import <Foundation/Foundation.h>
 4 #import <CoreData/CoreData.h>
 5 #import "AppDelegate.h"
 6 
 7 @interface SqliteViewController ()
 8 @property (nonatomic,weak) AppDelegate *appDelete;
 9 @property (nonatomic) int nameCount;
10 @end
11 
12 @implementation SqliteViewController
13 
14 - (void)viewDidLoad {
15     [super viewDidLoad];
16     self.nameCount = 1;
17     // Do any additional setup after loading the view.
18     self.appDelete = (AppDelegate *)[UIApplication sharedApplication].delegate;
19 }
20 
21 - (void)didReceiveMemoryWarning {
22     [super didReceiveMemoryWarning];
23     // Dispose of any resources that can be recreated.
24 }

 

 
5.1 新增實體
第一步:呼叫NSEntityDescription的 insertNewObjectForEntityForName:(NSString *) inManagedObjectContext:(NSManagedObjectContext *)方法,第一個引數為實體名,第二個引數為上下文物件
第二部:為新實體設定屬性
第三部:呼叫NSManagedObjectContext物件的save方法儲存。
 1 //新增操作
 2 - (IBAction)btnAdd_Tap:(id)sender {
 3     //建立一個新實體
 4     EventEntity *ee = [NSEntityDescription insertNewObjectForEntityForName:@"EventEntity" inManagedObjectContext:self.appDelete.managedObjectContext];
 5     //給實體設定屬性
 6     ee.happenDate = [NSDate date];
 7     ee.name = [NSString stringWithFormat:@"名字%d",self.nameCount++];
 8     
 9     //定義NSError物件接收錯誤資訊
10     NSError *error;
11     if ([self.appDelete.managedObjectContext save:&error]) {
12         [[[UIAlertView alloc] initWithTitle:@"新增操作" message:[NSString stringWithFormat:@"新增成功,新增的實體的name是:%@",ee.name] delegate:nil cancelButtonTitle:@"好的" otherButtonTitles:nil, nil] show];
13     }else
14     {
15         NSLog(@"儲存時出現錯誤:%@,%@",error,[error userInfo]);
16     }
17 }

 

 5.2 刪除實體
 1 //刪除操作
 2 - (IBAction)btnRemove_Tap:(id)sender {
 3     //獲取要刪除的實體
 4     EventEntity *entity = [self getEntityByName:@"名字1"];
 5     //從上下文物件中刪除該實體
 6     [self.appDelete.managedObjectContext deleteObject:entity];
 7     NSError *error;
 8     if (![self.appDelete.managedObjectContext save:&error]) {
 9         NSLog(@"刪除時出現錯誤:%@,%@",error,[error userInfo]);
10     }
11 }

5.3 修改實體

 1 //更新操作
 2 - (IBAction)btnUpdate_Tap:(id)sender {
 3     //獲取要刪除的實體
 4     EventEntity *entity = [self getEntityByName:@"名字1"];
 5     //修改實體屬性
 6     entity.happenDate = [NSDate date];
 7     NSError *error;
 8     if (![self.appDelete.managedObjectContext save:&error]) {
 9         NSLog(@"刪除時出現錯誤:%@,%@",error,[error userInfo]);
10     }
11 }

5.4 查詢

 1 //根據名字查詢一個物件
 2 -(EventEntity *)getEntityByName:(NSString *) name
 3 {
 4     //建立抓取資料的請求物件
 5     NSFetchRequest *request = [[NSFetchRequest alloc] init];
 6     
 7     //設定要抓取哪種型別的實體
 8     NSEntityDescription *des = [NSEntityDescription entityForName:@"EventEntity" inManagedObjectContext:self.appDelete.managedObjectContext];
 9     
10     //設定抓取實體
11     [request setEntity:des];
12     //定義抓取條件
13     NSPredicate * qcmd = [NSPredicate predicateWithFormat:@"name = %@ ",name];
14     [request setPredicate:qcmd];
15     
16     NSError *error = nil;
17     //執行查詢請求
18     NSArray *result = [[self.appDelete.managedObjectContext executeFetchRequest:request error:&error] copy];
19     if (error!=nil) {
20         NSLog(@"查詢單個時出現錯誤:%@,%@",error,[error userInfo]);
21         return nil;
22     }
23     if (result.count==0) {
24         return nil;
25     }
26     return result[0];
27 }
28 
29 //獲得所有實體
30 -(NSArray *)getAllEntities
31 {
32     //建立抓取資料的請求物件
33     NSFetchRequest *request = [[NSFetchRequest alloc] init];
34     
35     //設定要抓取哪種型別的實體
36     NSEntityDescription *des = [NSEntityDescription entityForName:@"EventEntity" inManagedObjectContext:self.appDelete.managedObjectContext];
37     
38     //設定抓取實體
39     [request setEntity:des];
40     
41     NSError *error = nil;
42     //執行查詢請求
43     NSArray *result = [[self.appDelete.managedObjectContext executeFetchRequest:request error:&error] copy];
44     //如果沒有資料返回nil
45     if (error!=nil && result == 0) {
46         return nil;
47     }
48     return result;
49 
50 }

 

 
 
 

相關文章