iOS數(shù)據(jù)存儲(chǔ)的五種方式(含F(xiàn)MDB,CoreData使用)

iOS數(shù)據(jù)存儲(chǔ)通常有以下五種方式:
1、Plist 2、NSUserDefaults 3、NSkeyedArchiver 4、SQLite 5、CoreData

等不及想看項(xiàng)目的同學(xué)點(diǎn)這兒demo

1、Plist

可被序列化的通常有以下幾種類型:
NSString(含NSMutableString),NSArray(含NSMutableArray), NSDictionary(含NSMutableDictionary),NSData(含 NSMutableData),NSNumber,NSDate

使用方法

  • 不在工程中新建plist文件

先創(chuàng)建一個(gè)plist的存儲(chǔ)路徑

NSString *docuPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSString *plistPath = [docuPath stringByAppendingPathComponent:@"hooyking.plist"];

以NSString保存示例

NSError *error = nil;
[@"張三" writeToFile:plistPath atomically:YES encoding:NSUTF8StringEncoding error:&error];

NSString數(shù)據(jù)取出

NSError *error = nil;
NSString *string = [NSString stringWithContentsOfFile:plistPath encoding:NSUTF8StringEncoding error:&error];
  • 在工程中新建一個(gè)plist文件


    plist.png

以NSArray保存示例

NSString *customerPlistPath = [[NSBundle mainBundle] pathForResource:@"HK" ofType:@"plist"];
NSArray *nameArray = @[@"first",@"last"];
[nameArray writeToFile:customerPlistPath atomically:YES];

NSArray數(shù)據(jù)取出

NSArray *customerPlistArray = [NSArray arrayWithContentsOfFile:customerPlistPath];
NSLog(@"項(xiàng)目中新建的plist文件保存的數(shù)據(jù)%@",customerPlistArray);

2、NSUserDefaults

NSUserDefaults支持的數(shù)據(jù)類型通常有以下幾種:
NSNumber(CGFloat、NSInteger、int、float、double), NSString(含NSMutableString),NSData(含NSMutableData,NSArray(含NSMutableArray),NSDictionary(含NSMutableDictionary),BOOL

  • 基本數(shù)據(jù)類型
    NSUserDefaults存儲(chǔ)的對(duì)象全是不可變的,即使存進(jìn)去的是可變的,取出來(lái)也是不可變的,如NSMutableArray存進(jìn)去,取出來(lái)就是NSArray了。

以NSString保存示例

NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud setObject:self.textField.text forKey:@"userDefaultKey"];
[ud synchronize];

NSString數(shù)據(jù)取出

NSString *text = [ud objectForKey:userDefaultKeyStr];
NSLog(@"取出的數(shù)據(jù)%@",text);
  • 自定義類型
    使用NSUserDefaults保存自定義類型,自定義類型必須遵循NSCoding協(xié)議,下面以PersonModel示例。

PersonModel.h中遵循<NSCoding>

PersonModel.h.png

PersonModel.m中實(shí)現(xiàn)解歸檔

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

//解檔
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeIntegerForKey:@"age"];
    }
    return self;
}

保存數(shù)據(jù)

NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
PersonModel *model = [PersonModel new];
model.name = @"張哈哈";
model.age = 10;
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:model];
[ud setObject:data forKey:@"customerObjectKey"];
[ud synchronize];

取出數(shù)據(jù)

NSData *data = [ud objectForKey:@"customerObjectKey"];
PersonModel *model = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@"名字:%@--年齡:%zd",model.name,model.age);

3、NSKeyedArchiver

這里的后綴名用了.data,實(shí)際上用什么后綴名都無(wú)所謂的。

  • 單個(gè)普通數(shù)據(jù)的歸解檔

文件路徑

NSString *docuPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"歸檔文件路徑:%@",docuPath);
NSString *singleCommonFilePath = [docuPath stringByAppendingPathComponent:@"singleCommon.data"];

歸檔

NSString *singleString = @"單個(gè)普通數(shù)據(jù)的歸檔看看如何?";
BOOL singleSuccess = [NSKeyedArchiver archiveRootObject:singleString toFile:singleCommonFilePath];
if (singleSuccess) {
    NSLog(@"單個(gè)普通數(shù)據(jù)歸檔成功");
} else {
    NSLog(@"單個(gè)普通數(shù)據(jù)歸檔失敗");
}

解檔

NSString *singleString = [NSKeyedUnarchiver unarchiveObjectWithFile:singleCommonFilePath];
NSLog(@"單個(gè)普通數(shù)據(jù)的解檔:%@",singleString);
  • 多個(gè)普通數(shù)據(jù)的歸解檔

文件路徑

NSString *docuPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"歸檔文件路徑:%@",docuPath);
NSString *multipleCommonFilePath = [docuPath stringByAppendingPathComponent:@"multipleCommon.data"];

歸檔

NSInteger age = 20;
NSString *name = @"張三";
NSArray *toies = @[@"柯尼賽格",@"百達(dá)斐麗",@"陸家嘴100套房"];
NSMutableData *mutableData = [[NSMutableData alloc] init];
NSKeyedArchiver *multipleKeyArchiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mutableData];
[multipleKeyArchiver encodeInteger:age forKey:@"age"];
[multipleKeyArchiver encodeObject:name forKey:@"name"];
[multipleKeyArchiver encodeObject:toies forKey:@"toies"];
[multipleKeyArchiver finishEncoding];//完成歸檔
BOOL multipleSuccess = [mutableData writeToFile:multipleCommonFilePath atomically:YES];//寫入文件
if (multipleSuccess) {
    NSLog(@"多個(gè)普通數(shù)據(jù)歸檔成功");
} else {
    NSLog(@"多個(gè)普通數(shù)據(jù)歸檔失敗");
}

解檔

NSMutableData *mutableData = [NSMutableData dataWithContentsOfFile:multipleCommonFilePath];
NSKeyedUnarchiver *keyedUnarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:mutableData];
NSInteger age = [keyedUnarchiver decodeIntegerForKey:@"age"];
NSString *name = [keyedUnarchiver decodeObjectForKey:@"name"];
NSArray *toies = [keyedUnarchiver decodeObjectForKey:@"toies"];
[keyedUnarchiver finishDecoding];
NSLog(@"多個(gè)普通數(shù)據(jù)的解檔:年齡:%zd--名字:%@--玩具:%@,%@,%@",age,name,toies[0],toies[1],toies[2]);
  • 自定義對(duì)象的歸解檔

自定義對(duì)象的歸檔必須遵循NSCoding協(xié)議,當(dāng)然自定義對(duì)象還可以包含自定義對(duì)象,被包含自定義對(duì)象同樣需要遵循NSCoding協(xié)議,下面以CarModelEngineModel示例,CarModel包含EngineModel

CarModel.png

對(duì)于自定義對(duì)象,不論他是只保存這個(gè)對(duì)象還是對(duì)象的array,dictionary,set,只要此對(duì)象遵循了NSCoding協(xié)議,都可進(jìn)行歸檔

文件路徑

NSString *docuPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"歸檔文件路徑:%@",docuPath);
NSString *customerModelFilePath = [docuPath stringByAppendingPathComponent:@"car.data"];

歸檔

CarModel *car = [[CarModel alloc] init];
car.price = 50000000;
car.brand = @"布加迪威龍";
car.wheelArr = @[@"左前輪",@"右前輪",@"左后輪",@"右后輪"];

EngineModel *engine = [[EngineModel alloc] init];
engine.model = @"無(wú)敵旋風(fēng)";
engine.cylinderNumber = 100;
    
car.engine = engine;

BOOL success = [NSKeyedArchiver archiveRootObject:car toFile:customerModelFilePath];
if (success) {
    NSLog(@"自定義對(duì)象歸檔成功");
} else {
    NSLog(@"自定義對(duì)象歸檔失敗");
}

解檔

CarModel *car = [NSKeyedUnarchiver unarchiveObjectWithFile:customerModelFilePath];
NSLog(@"自定義對(duì)象的解檔:車價(jià)格:%.2f--車標(biāo):%@--車輪子:%@,%@,%@,%@--發(fā)動(dòng)機(jī)型號(hào):%@--發(fā)動(dòng)機(jī)氣缸數(shù):%zd",
car.price,car.brand,car.wheelArr[0],car.wheelArr[1],car.wheelArr[2],car.wheelArr[3],car.engine.model,car.engine.cylinderNumber);

4.SQLite

SQLite存儲(chǔ)類型通常有以下幾種:

NULL NULL值
REAL 浮點(diǎn)型(如CGFloat,float,double,不過(guò)都需要轉(zhuǎn)成NSNumber存)
INTEGER 整型(如NSInteger,int,不過(guò)都需要轉(zhuǎn)成NSNumber存)
TEXT 文本類(如NSString)
BLOB 二進(jìn)制(如圖片、文件NSData

注意這個(gè)插入的數(shù)據(jù)那些都是對(duì)象,text對(duì)應(yīng)NSString,blob對(duì)應(yīng)NSData,integer對(duì)應(yīng)NSNumber

通常我們不直接使用系統(tǒng)的SQLite,而是用FMDB,它是對(duì)SQLite的封裝,使用更加優(yōu)美。

下面就詳細(xì)說(shuō)說(shuō)FMDB的使用

數(shù)據(jù)庫(kù)路徑及初始化FMDatabase

NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
NSLog(@"documentPath:%@",path);
NSString *dbpath = [path stringByAppendingPathComponent:@"hooyking.db"];
FMDatabase *db = [FMDatabase databaseWithPath:dbpath];
self.myDb = db;

對(duì)表操作后記得一定要調(diào)用close方法

  • 創(chuàng)建表
- (void)createTable {
    if ([_myDb open]) {
        //這兒創(chuàng)建了一個(gè)列有 name|sex|age|nickname|phoneNum|nativePlace|photo 的名字為personTable的表
        BOOL result = [_myDb executeUpdate:@"create table if not exists personTable (name text, sex integer, age integer, nickname text, phoneNum text, nativePlace text, photo blob)"];
        if (result) {
            NSLog(@"創(chuàng)建表成功");
        }
        else {
            NSLog(@"創(chuàng)建表失敗");
        }
        [_myDb close];
    }
}
  • 插入數(shù)據(jù)
- (void)insertData {
    if ([_myDb open]) {
        BOOL result = [_myDb executeUpdate:@"insert into personTable (name, sex, age, nickname, phoneNum, nativePlace, photo) values (?,?,?,?,?,?,?)",@"JDX",[NSNumber numberWithInteger:1],[NSNumber numberWithInteger:18], @"hooyking", [NSNumber numberWithInteger:13888888888],@"sichuan",[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"picture" ofType:@"jpg"]]];
        if (result) {
            NSLog(@"添加數(shù)據(jù)成功");
        }
        else {
            NSLog(@"添加數(shù)據(jù)失敗");
        }
        [_myDb close];
    }
}
  • 刪除數(shù)據(jù)
- (void)deleteData {
    //刪除這個(gè)表里nickname為hooyking的所有數(shù)據(jù),列沒(méi)有刪除,依然存在
    if ([_myDb open]) {
        BOOL result = [_myDb executeUpdate:@"delete from personTable where nickname = ?",@"hooyking"];
        if (result) {
            NSLog(@"刪除數(shù)據(jù)成功");
        }
        else {
            NSLog(@"刪除數(shù)據(jù)失敗");
        }
        [_myDb close];
    }
}
  • 修改數(shù)據(jù)
- (void)updateData {
    if ([_myDb open]) {
        BOOL result = [_myDb executeUpdate:@"update personTable set age = ? where nickname = ?",[NSNumber numberWithInteger:25],@"hooyking"];
        if (result) {
            NSLog(@"修改數(shù)據(jù)成功");
        }
        else {
            NSLog(@"修改數(shù)據(jù)失敗");
        }
        [_myDb close];
    }
}
  • 查詢數(shù)據(jù)
- (void)selectData {
    if ([_myDb open]) {
        //查詢多條數(shù)據(jù)
        FMResultSet *res = [_myDb executeQuery:@"select name, age from personTable"];
        while ([res next]) {
            NSString *name = [res stringForColumn:@"name"];
            NSInteger age = [res intForColumn:@"age"];
            NSLog(@"姓名:%@----年齡:%ld",name,age);
        }
        
        //查詢一條數(shù)據(jù)
        NSLog(@"年齡為25的人:%@",[_myDb stringForQuery:@"select name from personTable where age = ?",@25]);
        
        [_myDb close];
    }
}
  • 建多張表,插入,查詢多個(gè)數(shù)據(jù)等
- (void)moreOperate {
    if ([_myDb open]) {
        //創(chuàng)建表
        NSString *createSql = @"create table if not exists studentsTable1 (id integer, name text, sex integer);"
                               "create table if not exists studentsTable2 (id integer, name text, sex integer);"
                               "create table if not exists studentsTable3 (id integer, name text, sex integer);";
        BOOL createResult = [_myDb executeStatements:createSql];
        if (createResult) {
            NSLog(@"創(chuàng)建多張表成功");
        }
        else {
            NSLog(@"創(chuàng)建多張表失敗");
        }
        //*********************************插入多條數(shù)據(jù)(這里涉及到線程安全)**************************************
        
        //**********************方法一*********************
        NSString *insertSql = @"insert into studentsTable1 (id, name, sex) values ('100', '張三', '1');"
                               "insert into studentsTable2 (id, name, sex) values ('200', '李四', '1');"
                               "insert into studentsTable3 (id, name, sex) values ('300', '如花', '0');";
        BOOL insertResult = [_myDb executeStatements:insertSql];
        if (insertResult) {
            NSLog(@"插入數(shù)據(jù)成功");
        }
        else {
            NSLog(@"插入數(shù)據(jù)失敗");
        }
        
        //*********************方法二**********************
        //看這個(gè)方法:moreQueue
        
        
        //查詢數(shù)據(jù)
        NSString *selectSql = @"select * from studentsTable1;"
                               "select * from studentsTable2;"
                               "select * from studentsTable3;";
        BOOL selectResult = [_myDb executeStatements:selectSql withResultBlock:^int(NSDictionary *dictionary) {
            NSLog(@"moreOperate查詢到的結(jié)果:%@", [[dictionary allValues] componentsJoinedByString:@","]);
            return 0;
        }];
        if (selectResult) {
            NSLog(@"查詢成功");
        }
        else {
            NSLog(@"查詢失敗");
        }
        [_myDb close];
    }
}
  • 多個(gè)數(shù)據(jù)插入線程安全
- (void)moreQueue {
    //方法二里面線程安全又有兩種方式,ok繼續(xù)看
    if ([_myDb open]) {
        NSString *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
        NSString *dbpath = [path stringByAppendingPathComponent:@"hooyking.db"];
        FMDatabaseQueue *dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbpath];
        //第一種(一般就用這種就能保證線程安全了,那條數(shù)據(jù)有錯(cuò),那么有錯(cuò)那條就不會(huì)插入進(jìn)去,例如id改為i,自己看效果)
        [dbQueue inDatabase:^(FMDatabase *db) {
            [db executeUpdate:@"insert into studentsTable1 (id, name, sex) values (?,?,?)",[NSNumber numberWithInteger:500], @"王五", [NSNumber numberWithInteger:1]];
            [db executeUpdate:@"insert into studentsTable2 (id, name, sex) values (?,?,?)",[NSNumber numberWithInteger:600], @"陸六", [NSNumber numberWithInteger:1]];
            [db executeUpdate:@"insert into studentsTable3 (id, name, sex) values (?,?,?)",[NSNumber numberWithInteger:700], @"史真香", [NSNumber numberWithInteger:0]];
        }];
        //第二種事務(wù)(當(dāng)插入數(shù)據(jù)有錯(cuò)時(shí),直接取消將插入的數(shù)據(jù),可以改下列試試,例如id改為i,自己看效果)
//        [dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
//            BOOL res1 = [db executeUpdate:@"insert into studentsTable1 (id, name, sex) values (?,?,?)",[NSNumber numberWithInteger:500], @"王五", [NSNumber numberWithInteger:1]];
//            BOOL res2 = [db executeUpdate:@"insert into studentsTable2 (id, name, sex) values (?,?,?)",[NSNumber numberWithInteger:600], @"陸六", [NSNumber numberWithInteger:1]];
//            BOOL res3 = [db executeUpdate:@"insert into studentsTable3 (id, name, sex) values (?,?,?)",[NSNumber numberWithInteger:700], @"史真香", [NSNumber numberWithInteger:0]];
//            if (!res1 || !res2 || !res3) { //我這樣寫就是三條任何一條有錯(cuò),這三條就一條都不插入,這個(gè)判斷條件若是不寫,那就會(huì)默認(rèn)哪一條有錯(cuò),那一條就不會(huì)加入,但是其他的正確的會(huì)插入
//                *rollback = YES;
//            }
//            [db executeUpdate:@"insert into studentsTable3 (id, name, sex) values (?,?,?)",[NSNumber numberWithInteger:800], @"你真溜", [NSNumber numberWithInteger:0]];
//        }];
    
        //查詢數(shù)據(jù)
        NSString *selectSql = @"select * from studentsTable1;"
                               "select * from studentsTable2;"
                               "select * from studentsTable3;";
        BOOL selectResult = [_myDb executeStatements:selectSql withResultBlock:^int(NSDictionary *dictionary) {
            NSLog(@"moreQueue查詢到的結(jié)果:%@", [[dictionary allValues] componentsJoinedByString:@","]);
            return 0;
        }];
        if (selectResult) {
            NSLog(@"查詢成功");
        }
        else {
            NSLog(@"查詢失敗");
        }
        
        [_myDb close];
    }
}
  • 對(duì)列的操作

  • 添加列

- (void)addColumn {
    if ([_myDb open]) {
        //這兒添加了添加名字為temp類型為text的列
        BOOL addColumnRes = [_myDb executeUpdate:@"alter table studentsTable1 add temp text"];
        if (addColumnRes) {
            NSLog(@"添加列成功");
        }
        else {
            NSLog(@"添加列失敗");
        }
        
        [_myDb close];
    }
}
  • 刪除列
    SQLite不支持alter對(duì)列進(jìn)行修改與刪除的方法來(lái)的,所以要?jiǎng)h除列的替代方式為新建一個(gè)沒(méi)有你要?jiǎng)h除的列的表
    第一步:create table testTable(id integer, name text, sex integer);創(chuàng)建一個(gè)新表testTable,這個(gè)表沒(méi)有列temp了;
    第二步:insert into testTable select id, name, sex from studentsTable1;這兒完成了將表studentsTable1列id name sex中的全部數(shù)據(jù)插入到了表testTable中;
    第三步:drop table if exists studentsTable1;刪除原來(lái)的表studentsTable1;
    第四步:alter table testTable rename to studentsTable1;將testTable重命名為studentsTable1,若是你要修改列名,方式和刪除一樣,可自己操作一下。

  • 刪除表

- (void)dropTable {
    //銷毀這張表(即這個(gè)表刪除后就不存在了)
    if ([_myDb open]) {
        BOOL result = [_myDb executeUpdate:@"drop table if exists personTable"];
        if (result) {
            NSLog(@"銷毀表成功");
        }
        else {
            NSLog(@"銷毀表失敗");
        }
        [_myDb close];
    }
}

5、CoreData

新建項(xiàng)目時(shí)可勾選Use Core Data,勾選之后創(chuàng)建的項(xiàng)目就自帶CoreData了


勾選Use Core Data.png

若是不勾選,新建的項(xiàng)目就沒(méi)有CoreData文件,想使用CoreData就要通過(guò)New File選擇Data Model

不勾選Use Core Data.png

建好之后為如下圖所示


CoreData文件剛建好.png

點(diǎn)擊下方Add Entity添加實(shí)體

這兒我們添加Teacher與Student實(shí)體

Teacher實(shí)體添加好后.png
Teacher實(shí)體設(shè)置關(guān)聯(lián)關(guān)系后.png
Student實(shí)體設(shè)置關(guān)聯(lián)關(guān)系后.png

右側(cè)Relationship設(shè)置

Properties
transient:設(shè)置當(dāng)前屬性是否只存在于內(nèi)存,不被持久化到本地,如果設(shè)置為YES,關(guān)聯(lián)關(guān)系屬性就不參與持久化操作。transient設(shè)置為YES一般存儲(chǔ)一些在內(nèi)存中緩存的數(shù)據(jù),如存儲(chǔ)臨時(shí)數(shù)據(jù),當(dāng)app殺死后數(shù)據(jù)不會(huì)存在本地,該選項(xiàng)默認(rèn)NO。
optional: 設(shè)置向MOC保存數(shù)據(jù)時(shí),這個(gè)屬性是否必須有值。設(shè)置為NO時(shí),MOC進(jìn)行操作時(shí),若是無(wú)值,會(huì)失敗并返回一個(gè)error,該選項(xiàng)默認(rèn)YES。

Delete Rule
設(shè)置關(guān)聯(lián)屬性的刪除規(guī)則。一共四個(gè)值:這兒一般選后三個(gè)值,當(dāng)選No Action時(shí),Xcode也會(huì)報(bào)警告,讓設(shè)置一個(gè)關(guān)聯(lián)關(guān)系。
No Action:當(dāng)前實(shí)體刪除后對(duì)關(guān)聯(lián)實(shí)體無(wú)任何操作,也不會(huì)將關(guān)聯(lián)對(duì)象的關(guān)聯(lián)屬性指向nil,刪除后使用關(guān)聯(lián)對(duì)象的關(guān)聯(lián)屬性,可能會(huì)導(dǎo)致其他問(wèn)題。
Nullify:刪除后會(huì)將關(guān)聯(lián)實(shí)體的關(guān)聯(lián)屬性指向nil,delete Rule默認(rèn)值。
Cascade:刪除當(dāng)前對(duì)象后,會(huì)將與之關(guān)聯(lián)的實(shí)體也一并刪除。
Deny:在刪除當(dāng)前實(shí)體時(shí),如果當(dāng)前對(duì)象還指向其他關(guān)聯(lián)對(duì)象,則當(dāng)前實(shí)體不能被刪除。

Type
設(shè)置當(dāng)前實(shí)體與關(guān)聯(lián)實(shí)體的關(guān)聯(lián)關(guān)系
To One:當(dāng)前實(shí)體只可持有1個(gè)關(guān)聯(lián)實(shí)體(默認(rèn)值)
To Many:當(dāng)前實(shí)體只可持有多個(gè)關(guān)聯(lián)實(shí)體

Count只有選擇To Many時(shí)才有
設(shè)置最小值與最大值,默認(rèn)值不設(shè)置
Minimum:最小值
Maximum:最大值

Advanced
設(shè)置索引
indexed: 設(shè)置當(dāng)前屬性是否是索引。添加索引后可以提升檢索速度,但是對(duì)于刪除操作,刪除索引后其他地方還需要做出相應(yīng)的變化,所以速度會(huì)比較慢,默認(rèn)值NO。

Spotlight
Store in External Record File: 當(dāng)存儲(chǔ)二進(jìn)制文件時(shí),如果遇到比較大的文件,是否存儲(chǔ)在存儲(chǔ)區(qū)之外。如果選擇YES,存儲(chǔ)文件大小超過(guò)1MB的文件,都會(huì)存儲(chǔ)在存儲(chǔ)區(qū)之外。否則大型文件存儲(chǔ)在存儲(chǔ)區(qū)內(nèi),會(huì)造成SQLite進(jìn)行表操作時(shí),效率受到影響,默認(rèn)值NO。

設(shè)置好關(guān)系后創(chuàng)建模型文件
Xcode->Editor->Create NSManageredObject Subclass 勾選兩個(gè)實(shí)體,創(chuàng)建好后會(huì)報(bào)錯(cuò),在如下圖里找到文件,移除后就沒(méi)了

build Phases刪除四個(gè)文件.png

你可以在student屬性里看到如此這般
@property (nullable, nonatomic, retain) NSSet<Teacher *> *teachers;
你可以在Teacher屬性里看到如此這般
@property (nullable, nonatomic, retain) NSSet<Student *> *students;

  • 創(chuàng)建CoreData數(shù)據(jù)庫(kù)
- (void)createCoreDataLite {
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreData" withExtension:@"momd"];//CoreData為你自定義的CoreData文件名,momd為固定的類型
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"coreData.sqlite"];
    NSLog(@"數(shù)據(jù)庫(kù)地址%@",path);
    NSURL *sqlURL = [NSURL fileURLWithPath:path];
    NSError *error = nil;
    [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlURL options:nil error:&error];
    if (error) {
        NSLog(@"錯(cuò)誤%@",error);
    } else {
        NSLog(@"創(chuàng)建數(shù)據(jù)庫(kù)成功,如果已添加此數(shù)據(jù)庫(kù),就算再次調(diào)用也不用重復(fù)添加,直接使用以前的");
    }
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    context.persistentStoreCoordinator = store;
    self.context = context;
}
  • 添加數(shù)據(jù)
- (void)insertData {
    Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.context];
    student.name = [NSString stringWithFormat:@"Student%d",arc4random()%100];
    student.age = arc4random()%20;
    student.sex = arc4random()%2 == 0 ?  @"女" : @"男";

    Teacher *teacher = [NSEntityDescription insertNewObjectForEntityForName:@"Teacher" inManagedObjectContext:self.context];
    teacher.name = [NSString stringWithFormat:@"Teacher%d",arc4random()%100];
    teacher.age = arc4random()%60;
    teacher.students = [NSSet setWithArray:@[student]];
    
    NSError *error = nil;
    if ([self.context save:&error]) {
        NSLog(@"插入成功");
    } else {
        NSLog(@"插入失敗");
    }
}
  • 刪除數(shù)據(jù)
- (void)deleteData {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Teacher"];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age < 50"];
    request.predicate = predicate;
    NSArray *deleteArray = [self.context executeFetchRequest:request error:nil];
    for (Teacher *model in deleteArray) {
        NSLog(@"老師的學(xué)生%@",model.students);
        [self.context deleteObject:model];
    }
    NSError *error = nil;
    if ([self.context save:&error]) {
        NSLog(@"刪除成功");
    } else {
        NSLog(@"刪除失敗%@",error);
    }
}
  • 更新數(shù)據(jù)
- (void)updateData {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Teacher"];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age < 45"];
    request.predicate = predicate;
    NSArray *updateArray = [self.context executeFetchRequest:request error:nil];
    for (Teacher *model in updateArray) {
        model.name = @"張三";
    }
    NSError *error = nil;
    if ([self.context save:&error]) {
        NSLog(@"更新成功");
    } else {
        NSLog(@"更新失敗");
    }
}
  • 查詢數(shù)據(jù)
- (void)findData {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Teacher"];
    //此處可寫查詢條件(更多條件設(shè)定可瀏覽器自行搜索)
//    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age < 50"];
//    request.predicate = predicate;
    //此處可寫排序條件(這兒按年齡排序)
//    NSSortDescriptor *ageSort = [NSSortDescriptor sortDescriptorWithKey:@"age"ascending:YES];
//    request.sortDescriptors = @[ageSort];
    NSArray *resultArray = [self.context executeFetchRequest:request error:nil];
    self.dataMArray = [resultArray mutableCopy];
    [self.tableView reloadData];
}
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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