iOS中常用數(shù)據(jù)持久化總結(jié)

在項(xiàng)目中我們常需要根據(jù)需求存儲(chǔ)一些信息,而數(shù)據(jù)持久化就顯得非常必要了,在這里我對(duì)數(shù)據(jù)持久化做個(gè)總結(jié)。
在說(shuō)數(shù)據(jù)持久化之前,先提一個(gè)概念,沙盒。相信大家對(duì)他并不陌生,iOS程序默認(rèn)情況下只能訪問(wèn)程序自己的目錄,這個(gè)目錄被稱(chēng)為沙盒。
沙盒路徑下有好幾個(gè)文件夾,每個(gè)文件夾都有自己的特性。詳細(xì)代碼如下:

//存放應(yīng)用程序的源文件,app
    NSString *pathOne = [[NSBundle mainBundle] bundlePath];
    NSLog(@"%@", pathOne);
    
    //最常用的目錄Documents,iTunes同步該應(yīng)用時(shí)會(huì)同步此文件夾中的內(nèi)容,適合存儲(chǔ)重要數(shù)據(jù)。
    NSString *pathTwo = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    NSLog(@"%@", pathTwo);
    
    //caches:iTunes不會(huì)同步此文件夾,適合存儲(chǔ)體積大,不需要備份的非重要數(shù)據(jù)。Preferences:NSUserDefaults中存儲(chǔ),iTunes同步該應(yīng)用時(shí)會(huì)同步此文件夾中的內(nèi)容,通常保存應(yīng)用的設(shè)置信息。
    NSString *pathThree = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSLog(@"%@", pathThree);
    
    //iTunes不會(huì)同步此文件夾,系統(tǒng)可能在應(yīng)用運(yùn)行時(shí)就刪除該目錄下的文件,所以此目錄適合應(yīng)用中的一些臨時(shí)文件,用完就刪除
    NSString *pathFour = NSTemporaryDirectory();
    NSLog(@"%@",pathFour);

1.plist文件

plist文件是將某些特定的類(lèi),通過(guò)xml的方式保存在目錄中。
可以被序列化的類(lèi)型只有如下幾種:NSArray NSMutableArray NSDictionary NSMutableDictionary NSData NSMutableData NSString NSMutableString NSNumber NSDate

詳細(xì)代碼如下:

    //1.獲取文件路徑
    NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
    NSString *fileName = [path stringByAppendingPathComponent:@"fei.plist"];
    //2.存儲(chǔ)
    NSArray *array = @[@"1",@"2",@"3",@"4"];
    [array writeToFile:fileName atomically:YES]; //atomically表示是否需要先寫(xiě)入一個(gè)輔助文件,再把輔助文件拷貝到目標(biāo)文件地址。這是更安全的寫(xiě)入文件方法,一般都寫(xiě)YES。
    
    //3.讀取
    NSArray *result  = [NSArray arrayWithContentsOfFile:fileName];
    NSLog(@"%@", result);

2.NSUserDefaults

先上代碼,大家先看一下:

//1.獲得NSUserDefaults文件
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    //2.向文件中寫(xiě)入內(nèi)容
    [userDefaults setObject:@"獅子" forKey:@"貓科動(dòng)物"];
    [userDefaults setBool:YES forKey:@"公的母的"];
    [userDefaults setInteger:5 forKey:@"多大"];
    //3.立即同步
    [userDefaults synchronize];
    //4.讀取文件
    NSString *name = [userDefaults objectForKey:@"貓科動(dòng)物"];
    BOOL sex = [userDefaults boolForKey:@"公的母的"];
    NSInteger age = [userDefaults integerForKey:@"多大"];
    NSLog(@"%@, %d, %ld", name, sex, age);

一般在這里保存應(yīng)用程序的配置信息的(我們代駕項(xiàng)目中是把個(gè)人信息存儲(chǔ)在這里),一般不要在這里保存其他數(shù)據(jù)。
如果這里你沒(méi)有調(diào)用synchronize方法的話,系統(tǒng)會(huì)根據(jù)I/O情況不定時(shí)刻地保存到文件中。所以如果需要立即寫(xiě)入文件的就必須調(diào)用synchronize方法。

3.NSKeyedArchiver

歸檔在iOS中是另一種形式的序列化,只要遵循了NSCoding協(xié)議的對(duì)象都可以通過(guò)它實(shí)現(xiàn)序列化。由于決大多數(shù)支持存儲(chǔ)數(shù)據(jù)的Foundation和Cocoa Touch類(lèi)都遵循了NSCoding協(xié)議,因此,對(duì)于大多數(shù)類(lèi)來(lái)說(shuō),歸檔相對(duì)而言還是比較容易實(shí)現(xiàn)的。
1.需要在定義的類(lèi)中實(shí)現(xiàn)NSCoding協(xié)議 ,一個(gè)用來(lái)說(shuō)明如何將對(duì)象編碼到歸檔中,另一個(gè)說(shuō)明如何進(jìn)行解檔來(lái)獲取一個(gè)新對(duì)象。

//實(shí)現(xiàn)協(xié)議的方法
//解檔
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if ([super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];       
    }
    return self;
}

//歸檔
- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeInteger:self.age forKey:@"age"];
}

注意:如果需要?dú)w檔的類(lèi)是某個(gè)自定義類(lèi)的子類(lèi)時(shí),就需要在歸檔和解檔之前先實(shí)現(xiàn)父類(lèi)的歸檔和解檔方法。
2.接下來(lái)是使用,將創(chuàng)建類(lèi)的對(duì)象的數(shù)據(jù)進(jìn)行歸檔。

NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"maozhuxi.data"];
    Person *person = [[Person alloc] init];
    person.name = @"毛主席";
    person.age = 50;
    //將對(duì)象歸檔是調(diào)用NSKeyedArchiver的工廠方法archiveRootObject
    [NSKeyedArchiver archiveRootObject:person toFile:file];

然后在我們需要的地方解檔取出這些數(shù)據(jù)

    //需要從文件中解檔對(duì)象就調(diào)用NSKeyedUnarchiver的一個(gè)工廠方法 unarchiveObjectWithFile:即可。
    NSString *file = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"maozhuxi.data"];
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
    if (person) {
        NSLog(@"name == %@", person.name);
        NSLog(@"age == %ld", person.age);
    }

4.FMDB

大數(shù)據(jù)的存儲(chǔ)我們一般用FMDB,比如聊天中的信息一般是用FMDB存儲(chǔ)的(融云第三方就是這么存儲(chǔ)的。。。),他是在sqlite的基礎(chǔ)上進(jìn)行封裝的,因?yàn)閟qlite使用起來(lái)不是很好使,所以iOS的大神們封裝了這個(gè)FMDB,我也在這里記錄一下用法以及心得。
FMDB的下載地址:https://github.com/ccgus/fmdb
1.將FMDB第三方導(dǎo)入到工程中,如下圖:

Paste_Image.png

2.在工程文件中導(dǎo)入FMDB.h
3.創(chuàng)建數(shù)據(jù)庫(kù),并建表格。如下面代碼

- (void)openDataBase {
  //1.設(shè)置文件名
    NSString *filename = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"xiaoping.db"];
    //2.打開(kāi)數(shù)據(jù)庫(kù)文件,如果沒(méi)有會(huì)自動(dòng)創(chuàng)建一個(gè)文件
    _database = [FMDatabase databaseWithPath:filename];
    if (![_database open]) {
        NSLog(@"數(shù)據(jù)庫(kù)打開(kāi)失敗");
    }else {
        [_database executeUpdate:@"create table myTable(name,age,sex)" ];
    }
    [_database close];
    
}

在指定路徑下創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)文件,并在其中創(chuàng)建一個(gè)表格,分別包含三個(gè)屬性。
4.向表格中添加數(shù)據(jù),如下代碼:

- (void)addSQL {
    [_database open];
    BOOL b = [_database executeUpdateWithFormat:@"insert into myTable(name,age,sex) values (%@,%d,%@);",@"junjie",23,@"man"];
   BOOL c = [_database executeUpdateWithFormat:@"insert into myTable(name,age,sex) values (%@,%d,%@);",@"xiaohong",22,@"woman"];
    [_database close];
    b ? NSLog(@"junjie success"):NSLog(@"junjie fail");
    c ? NSLog(@"xiaohong success"):NSLog(@"xiaohong fail");
}

在這里添加了兩條數(shù)據(jù),分別是junjie和xiaohong,注意一下語(yǔ)法。
5.查詢(xún)表格中的數(shù)據(jù),如下代碼:

- (void)requireSQL {
    //取得資料
    [_database open];
    FMResultSet *rs = [_database executeQuery:@"select * from myTable"];
    while ([rs next]) {//遍歷一下
        NSString *name = [rs stringForColumn:@"name"];
        int age = [rs intForColumn:@"age"];
        NSString *sex = [rs stringForColumn:@"sex"];
        NSLog(@"name == %@, age == %d, sex == %@",name, age, sex);
    }

    
    
    //這里是找出對(duì)應(yīng)的人的對(duì)應(yīng)信息
    NSString *junjie_sex = [_database stringForQuery:@"select sex from myTable where name = ?",@"junjie"];
    NSString *xiaohong_sex = [_database stringForQuery:@"select sex from myTable where name = ?",@"xiaohong"];
    NSLog(@"junjie_sex == %@", junjie_sex);
    NSLog(@"xiaohong_sex == %@", xiaohong_sex);
    [rs close];
    [_database close];
}

6.刪除操作,代碼如下:

- (void)delegateSQL {
    [_database open];
    [_database executeUpdate:@"delete from myTable where name = 'junjie'"];
     [_database close];
}

上面,除了查詢(xún)是executeQuery語(yǔ)句,其余全是executeUpdate語(yǔ)句。對(duì)于sql語(yǔ)法不熟悉的童鞋,在這里參考一下我寫(xiě)的,如果還不明白,百度一下sql簡(jiǎn)單語(yǔ)法你就懂了(大學(xué)教的。。)
以上代碼敲出來(lái)后,有時(shí)候我們想通過(guò)圖形的方式查看,以前在大學(xué)學(xué)數(shù)據(jù)庫(kù)的時(shí)候 (那會(huì)還是windows),我們用的是MySQL,然后在dos下(終端)能夠?qū)⒈砀褚詧D文形式展現(xiàn)出來(lái),在這里我是用DB Browser工具操作的,如下圖:


Paste_Image.png

很直觀的看見(jiàn)你建的表格數(shù)據(jù)。

5.CoreData

1.新建一個(gè)工程,并勾選coredata選項(xiàng):


Paste_Image.png

2.建立好以后可以看到xxx.xcdatamodeld,在這里可以添加實(shí)體和實(shí)體的屬性。需要注意的是:實(shí)體名字必須以大寫(xiě)開(kāi)頭


Paste_Image.png

3.然后新建一個(gè)file,記得是NSManagedObject cubclass
Paste_Image.png

4.然后勾選自己的工程


Paste_Image.png

5.勾選建立的實(shí)體
Paste_Image.png

6.next后我們即可獲得四個(gè)文件
Paste_Image.png

7.在viewcontrller中導(dǎo)入<CoreData/CoreData.h>
"Student.h"
"Student+CoreDataProperties.h"

然后定義成員變量

{
    AppDelegate *app;
}

并在viewdidload中初始化

app = [UIApplication sharedApplication].delegate;

8.接下來(lái)是增刪改查

//增
- (void)coreDataAdd {
    //初始化,name后面跟的是剛建的那個(gè)實(shí)體
    Student *stu = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:[app managedObjectContext]];
   
    stu.name = [NSString stringWithFormat:@"junjie%d",arc4random()%10];
    stu.sex = @"man";
    stu.age = [NSString stringWithFormat:@"%d", arc4random() % 15];
    //保存
    [app.managedObjectContext save:nil];
}

//刪除
- (void)coreDataDelegate {
   //讀取這個(gè)類(lèi),entify:定義管理對(duì)象,managedObjectContext:被管理的對(duì)象上下文
    NSEntityDescription *entify = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:app.managedObjectContext];
    //建立請(qǐng)求,NSFetchRequest獲取數(shù)據(jù)的請(qǐng)求
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entify];
    
    //設(shè)置檢索條件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@",@"e3"];
    [request setPredicate:predicate];
    
    
    //遍歷所有學(xué)生,獲取所有學(xué)生的信息,存在數(shù)組array里面
    NSArray *array = [app.managedObjectContext executeFetchRequest:request error:nil];
    if (array.count) {
        for (Student *stu in array) {
            //刪除對(duì)象
            [app.managedObjectContext deleteObject:stu  ];
        }
        //保存結(jié)果
        [app.managedObjectContext save:nil];
        NSLog(@"delegate success");
    } else {
        NSLog(@"沒(méi)有檢索到數(shù)據(jù)");
    }
}

//改
- (void)coreDataUpdate {
 //讀取類(lèi)
    NSEntityDescription *entify = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:app.managedObjectContext];
    //建立請(qǐng)求
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    [request setEntity:entify];
    
    
    //建立檢索條件
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name != %@", @"xiaohong"];
    [request setPredicate:predicate];
    
    
    //遍歷所有學(xué)生,獲取所有學(xué)生的信息,存在數(shù)據(jù)array里面
    NSArray *array = [app.managedObjectContext executeFetchRequest:request error:nil];
    if (array.count) {
        for (Student *stu in array) {
            stu.name = @"xiaohong";
        }
        //保存
        [app.managedObjectContext save:nil];
        NSLog(@"修改完成");
    } else  {
        NSLog(@"沒(méi)有檢索結(jié)果");
    }
}

//查
- (void)coreDataSelect {
    //讀取這個(gè)類(lèi)
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:app.managedObjectContext];
    //建立請(qǐng)求
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    //建立請(qǐng)求的是哪一類(lèi)
    [request setEntity:entity];
    
    //遍歷所有學(xué)生,獲取所有學(xué)生的信息,存在數(shù)據(jù)array里面
    NSArray *array = [app.managedObjectContext executeFetchRequest:request error:nil];
    for (Student *stu in array) {
        NSLog(@"%@", stu.name);
    }
}

數(shù)據(jù)持久化常見(jiàn)的就這幾種,可以根據(jù)自己的需要選擇一到兩種使用。我一般用小數(shù)據(jù)存儲(chǔ)用NSUserDefaults,大數(shù)據(jù)存儲(chǔ)用FMDB,其他的相對(duì)來(lái)說(shuō)用的少。

最后,如果你喜歡我的文章,就給我大大的點(diǎn)個(gè)贊吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容