本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
ios数据存储的5种方式
manongba · 2088浏览 · 发布于2019-10-30 +关注

ios数据存储的5种方式

  • NSUserDefaults(Preference偏好设置)

  • plist存储

  • 归档

  • SQLite3

  • CoreData

应用沙盒

Document:适合存储重要的数据, iTunes同步应用时会同步该文件下的内容,(比如游戏中的存档)

Library/Preferences:通常保存应用的设置信息, 系统可能在应用没在运行时删除该目录下的文件,iTunes会同步Library/Caches:适合存储体积大,不需要备份的非重要数据,iTunes不同步该文件

tmp:保存应用的临时文件,用完就删除,系统可能在应用没在运行时删除该目录下的文件,iTunes不同步该文件


获取沙盒路径

Document:


//Document path    
NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
 
//Library path
NSString *libraryPath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES)[0];
 
//caches path
NSString *cachesPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
 
//Preferences path
NSString*preferencePath = [libraryPath stringByAppendingString:@"/Preferences"];
 
//tem path
NSString *tmpPath = NSTemporaryDirectory();
 
//app path
NSString *appPath = [[NSBundle mainBundle] bundlePath];

NSuserDefault

NSuserDefault适合存储轻量级的本地数据,支持的数据类型有:NSNumber,NSString,NSDate,NSArray,NSDictionary,BOOL,NSData


沙盒路径为 Library/Preferences

文件格式为 .plist


优点:


  1. 不需要关心文件名

  2. 快速进行键值对存储

  3. 直接存储基本数据类型


缺点:


1.不能存存取自定义数据类型,如果需要支持,需要自定义数据转为支持的类型;比如实现NSCoding协议的encodeWithCoder、initWithCoder。

- (IBAction)userDefaultSave:(id)sender {
    NSArray *testArray = @[@"test1", @"test2", @"test3"];
    [[NSUserDefaults standardUserDefaults] setObject:testArray forKey:@"arrayKey"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}


- (IBAction)userDefaultLoad:(id)sender {
    NSArray *testArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"arrayKey"];
    NSLog(@"%@", testArray);
}

plist存储

plist支持的数据类型:


NSArray;
NSMutableArray;
NSDictionary;
NSMutableDictionary;
NSData;
NSMutableData;
NSString;
NSMutableString;
NSNumber;
NSDate;
不支持BOOL
而且最外层好像要用`NSArray 或 NSDictionary,主要是使用writeToFile api写入指定目录


- (IBAction)plistSave:(id)sender {
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *filePath = [cachePath stringByAppendingPathComponent:@"testPlist.plist"];
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:@"ran" forKey:@"name"];
    [dict setObject:@"18" forKey:@"age"];
    [dict writeToFile:filePath atomically:YES];
}
 
- (IBAction)plistLoad:(id)sender {
    NSString *cachePath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *filePath = [cachePath stringByAppendingPathComponent:@"testPlist.plist"];
    
    NSDictionary *t = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"%@",t);
}

归档

存储自定义对象


首先新建Person类,并遵守NSCoding协议

@interface Person : NSObject<NSCoding>
 
@property(nonatomic, strong)NSString *name;
@property(nonatomic, strong)NSString *age;
 
@end


实现协议方法

@implementation Person
 
- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super init];
    if (self) {
        _name = [coder decodeObjectForKey:@"name"];
        _age = [coder decodeObjectForKey:@"age"];
    }
    return self;
}
 
- (void)encodeWithCoder:(NSCoder *)coder
{
 
    [coder encodeObject:self.name forKey:@"name"];
    [coder encodeObject:self.age forKey:@"age"];
 
}
@end


归档解档

- (IBAction)archive:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    
    Person *p1 = [[Person alloc] init];
    p1.name = @"ran";
    p1.age = @"18";
    
    [NSKeyedArchiver archiveRootObject:p1 toFile:filePath];
 
 
    //也可以使用这种方式写到Preferences personModel目录
    //NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    //NSData *data = [NSKeyedArchiver archivedDataWithRootObject:p1];
    //[userDefaults setObject:data forKey:@"personModel"];
    //[userDefaults synchronize];
 
 
}
 
- (IBAction)unarchive:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    
    Person *p1 = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath] ;
    
    NSLog(@"%@", p1.name);
    NSLog(@"%@", p1.age);
 
    //也可以使用这种方式取到Preferences personModel目录
    //NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    //Person *p1 = (Person *)[NSKeyedUnarchiver unarchiveObjectWithData:[userDefaults objectForKey:@"personModel"]];
    //NSLog(@"%@", p1.name);
    //NSLog(@"%@", p1.age);
    
}


但是这种方法只能存储一个对象,存储多个对象要采用如下的方法:

- (IBAction)archiveManyObject:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    
    NSMutableData *data = [[NSMutableData alloc] init];
    NSKeyedArchiver *archiver =  [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; //将数据区连接到NSKeyedArchiver对象
    
    Person *p1 = [[Person alloc] init];
    p1.name = @"ran1";
    p1.age = @"18";
    [archiver encodeObject:p1 forKey:@"person1"];
    
    Person *p2 = [[Person alloc] init];
    p2.name = @"ran2";
    p2.age = @"19";
    [archiver encodeObject:p2 forKey:@"person2"];
 
    [archiver finishEncoding];
    
    [data writeToFile:filePath atomically:YES];
}
 
- (IBAction)unarchiveManyObject:(id)sender {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentFilePath = paths.firstObject  ;
    NSString *filePath = [documentFilePath stringByAppendingPathComponent:@"personModel"];
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    
    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    Person *p1 =  [unarchiver decodeObjectForKey:@"person1"];
    Person *p2 =  [unarchiver decodeObjectForKey:@"person2"];
    [unarchiver finishDecoding];
    
    NSLog(@"%@", p1.name);
    NSLog(@"%@", p2.name);
}


SQLite3

数据库(splite):

splite是一个轻量级,跨平台的小型数据库,可移植性比较高,有着和MySpl几乎相同的数据库语句,以及无需服务器即可使用的优点:


数据库的优点:

  1. 该方案可以存储大量的数据,存储和检索的速度非常快.

  2. 能对数据进行大量的聚合,这样比起使用对象来讲操作要快.




数据库的缺点:

  1. 它没有提供数据库的创建方式

  2. 它的底层是基于C语言框架设计的, 没有面向对象的API, 用起来非常麻烦

  3. 发杂的数据模型的数据建表,非常麻烦

在实际开发中我们都是使用的是FMDB第三方开源的数据库,该数据库是基于splite封装的面向对象的框架.

#import "SqliteVC.h"
#import "Person.h"
@interface SqliteVC() {
    
    sqlite3 *_db;
 
}
@end
 
@implementation SqliteVC
 
- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSString *fileName = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"student.sqlite"];
    NSLog(@"fileName = %@",fileName);
    
    int result = sqlite3_open(fileName.UTF8String, &_db); //创建(打开)数据库,如果数据库不存在,会自动创建  数据库文件的路径必须以C字符串(而非NSString)传入
    
    if (result == SQLITE_OK) {
        NSLog(@"成功打开数据库");
        
        char *errorMesg = NULL;
        const char *sql = "create table if not exists t_person (id integer primary key autoincrement, name text, age integer);";
        int result = sqlite3_exec(_db, sql, NULL, NULL, &errorMesg); //sqlite3_exec()可以执行任何SQL语句,比如创表、更新、插入和删除操作。但是一般不用它执行查询语句,因为它不会返回查询到的数据
        
        if (result == SQLITE_OK) {
            NSLog(@"成功创建t_person表");
        } else {
            NSLog(@"创建t_person表失败:%s",errorMesg);
        }
        
    } else {
        NSLog(@"打开数据库失败");
    }
}
- (IBAction)insert:(id)sender {
    for (int i = 0; i < 30; i++) {
        
        NSString *name = [NSString stringWithFormat:@"person-%d",arc4random()%100];
        int age = arc4random() % 100;
        
        char *errorMesg = NULL;
        NSString *sql = [NSString stringWithFormat:@"insert into t_person (name,age) values ('%@',%d);",name, age];
        int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
        
        if (result == SQLITE_OK) {
            NSLog(@"添加数据成功");
        } else {
            NSLog(@"添加数据失败");
        }
    }
}
 
- (IBAction)delete:(id)sender {
    char *errorMesg = NULL;
    NSString *sql = @"delete from t_person where age >= 0";
    int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
    
    if (result == SQLITE_OK) {
        NSLog(@"删除成功");
    }else {
        NSLog(@"删除失败");
    }
}
 
- (IBAction)query:(id)sender {
    const char *sql = "select id, name, age from t_person;";  //"select id, name, age from t_person where age >= 50;"
    sqlite3_stmt *stmt = NULL;  //定义一个stmt存放结果集
    int result = sqlite3_prepare_v2(_db, sql, -1, &stmt, NULL); //检测SQL语句的合法性
    
    if (result == SQLITE_OK) {
        NSLog(@"查询语句合法");
        
        while (sqlite3_step(stmt) == SQLITE_ROW) {
            
            int ID = sqlite3_column_int(stmt, 0);
            const unsigned char *sname = sqlite3_column_text(stmt, 1);
            NSString *name = [NSString stringWithUTF8String:(const char *)sname];
            int age = sqlite3_column_int(stmt, 2);
            
            NSLog(@"%d %@ %d",ID, name, age);
        }
    } else {
        NSLog(@"查询语句非法");
    }
}
 
- (IBAction)update:(id)sender {
    NSString *sql = @"update t_person set name = '哈哈' where age > 60";
    char *errorMesg = NULL;
    int result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, &errorMesg);
    
    if (result == SQLITE_OK) {
        NSLog(@"更改成功");
    }else {
        
        NSLog(@"更改失败");
    }
}

 

coreData

coreData是苹果官方在iOS5之后推出的综合性数据库,其使用了对象关系映射技术,将对象转换成数据,将数据存储在本地的数据库中

coreData为了提高效率,需要将数据存储在不同的数据库中,比如:在使用的时候,最好是将本地的数据保存到内存中,这样的目的是访问速度比较快.


CoreData与SQLite进行对比


SQLite

1、基于C接口,需要使用SQL语句,代码繁琐

2、在处理大量数据时,表关系更直观

3、在OC中不是可视化,不易理解

 

 

CoreData

1、可视化,且具有undo/redo能力

2、可以实现多种文件格式:

    * NSSQLiteStoreType

    * NSBinaryStoreType

    * NSInMemoryStoreType

    * NSXMLStoreTyp

3、苹果官方API支持,与iOS结合更紧密

 

 

CoreData核心类与结构


NSManagedObjectContext(数据上下文)

  • 对象管理上下文,负责数据的实际操作(重要)

  • 作用:插入数据,查询数据,删除数据,更新数据


NSPersistentStoreCoordinator(持久化存储助理)

  • 相当于数据库的连接器

  • 作用:设置数据存储的名字,位置,存储方式,和存储时机


NSManagedObjectModel(数据模型)

  • 数据库所有表格或数据结构,包含各实体的定义信息

  • 作用:添加实体的属性,建立属性之间的关系

  • 操作方法:视图编辑器,或代码


NSManagedObject(被管理的数据记录)

  • 数据库中的表格记录


NSEntityDescription(实体结构)

  • 相当于表格结构


NSFetchRequest(数据请求)

  • 相当于查询语句


后缀为.xcdatamodeld的包

  • 里面是.xcdatamodel文件,用数据模型编辑器编辑

  • 编译后为.momd或.mom文件

aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy81NDM4MDI3LWY0ZWU5MDJiZDE0M2ViZTEucG5nP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXB8aW1hZ2VWaWV3Mi8yL3cvMTIwMC9mb3JtYXQvd2VicA.jpg

类关系图


开始创建coredata

步骤:

1.创建模型文件 [相当于一个数据库]

2.添加实体 [一张表]

3.创建实体类 [相当模型--表结构]

4.生成上下文 关联模型文件生成数据库


创建模型文件

New File -> iOS -> Core Data ->Data Model

创建实体

aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy81NDM4MDI3LWViNzRhMWQ1OTExMDgxMjkucG5nP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXB8aW1hZ2VWaWV3Mi8yL3cvMTIwMC9mb3JtYXQvd2VicA.jpg


创建实体

aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy81NDM4MDI3LTMyMTQzMDFiMjQwYWUzNjYucG5nP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXB8aW1hZ2VWaWV3Mi8yL3cvNTMwL2Zvcm1hdC93ZWJw.jpg

 

Codegen

创建实体类

aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy81NDM4MDI3LWI5OGYzZDUyNjg2N2Q4ZTgucG5nP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXB8aW1hZ2VWaWV3Mi8yL3cvMTAyNi9mb3JtYXQvd2VicA.jpg


创建实体类

创建结果如图所示:

aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy81NDM4MDI3LTg1Mzc4OWI3NTEwYTJkMGUucG5nP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXB8aW1hZ2VWaWV3Mi8yL3cvNTQ2L2Zvcm1hdC93ZWJw.jpg

 

创建结果

生成上下文 关联模型文件生成数据库,进行增删查改操作

#import "coredataVC.h"
#import <CoreData/CoreData.h>
#import "Student+CoreDataProperties.h"
 
@interface coredataVC ()
 
@property(nonatomic, strong)NSManagedObjectContext *context;
 
@end
 
@implementation coredataVC
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    //entity 记得勾选 language:objective-c 和 codegen:manual/none
    [self createSql];
}
 
- (void)createSql {
    //获取模型路径
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Person" withExtension:@"momd"];
    //根据模型文件创建模型对象
    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    
    //利用模型对象创建持久化存储助理
    NSPersistentStoreCoordinator *store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
    
    //数据库的名称和路径
    NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *sqlPath = [docStr stringByAppendingPathComponent:@"coreData.sqlite"];
    NSURL *sqlUrl = [NSURL fileURLWithPath:sqlPath];
    NSLog(@"数据库 path = %@", sqlPath);
    
    NSError *error = nil; //设置数据库相关信息 添加一个持久化存储库并设置类型和路径,NSSQLiteStoreType:SQLite作为存储库
    [store addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlUrl options:nil error:&error];
    
    if (error) {
        NSLog(@"添加数据库失败:%@",error);
    } else {
        NSLog(@"添加数据库成功");
    }
    
    //3、创建上下文 保存信息 对数据库进行操作 关联持久化助理
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    context.persistentStoreCoordinator = store;
    _context = context;
}
增
- (IBAction)insertClick:(id)sender {
    Student * student = [NSEntityDescription  insertNewObjectForEntityForName:@"Student"  inManagedObjectContext:_context];
    student.name = [NSString stringWithFormat:@"stu-%d",arc4random()%100];
    student.age = arc4random()%30;
    
    NSError *error = nil;
    if ([_context save:&error]) {
        NSLog(@"数据插入到数据库成功");
    }else{
        NSLog(@"数据插入到数据库失败");
    }
}
删
- (IBAction)deleteClick:(id)sender {
    //创建删除请求
    NSFetchRequest *deleRequest = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
    
    //删除条件 没有任何条件就是读取所有的数据
    //NSPredicate *pre = [NSPredicate predicateWithFormat:@"age < %d", 10];
    //deleRequest.predicate = pre;
    
    //返回需要删除的对象数组
    NSArray *deleArray = [_context executeFetchRequest:deleRequest error:nil];
    
    //从数据库中删除
    for (Student *stu in deleArray) {
        [_context deleteObject:stu];
    }
    
    NSError *error = nil;
    if ([_context save:&error]) {
        NSLog(@"删除数据成功");
    }else{
        NSLog(@"删除数据失败, %@", error);
    }
}
查
- (IBAction)queryClick:(id)sender {
    //创建查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
    
    //查询条件 没有任何条件就是读取所有的数据
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"age >= 0"];
    request.predicate = pre;
    
    // 从第几页开始显示 通过这个属性实现分页
    //request.fetchOffset = 0;
    // 每页显示多少条数据
    //request.fetchLimit = 6;
    
    //发送查询请求
    NSArray *resArray = [_context executeFetchRequest:request error:nil];
    
    //打印查询结果
    for (Student *stu in resArray) {
        NSLog(@"name=%@, age=%d",stu.name, stu.age);
    }
}
改
- (IBAction)updateClick:(id)sender {
    //创建查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"age >= 0"];
    request.predicate = pre;
    
    //发送请求
    NSArray *resArray = [_context executeFetchRequest:request error:nil];
    
    //修改
    for (Student *stu in resArray) {
        stu.name = @"ran";
    }
    
    NSError *error = nil;
    if ([_context save:&error]) {
        NSLog(@"更新数据成功");
    }else{
        NSLog(@"更新数据失败, %@", error);
    }
}
 
@end

 

相关推荐

android下vulkan与opengles纹理互通

talkchan · 1178浏览 · 2020-11-23 10:37:39
Android 使用RecyclerView实现轮播图

奔跑的男人 · 2175浏览 · 2019-05-09 17:11:13
微软发布新命令行工具 Windows Terminal

吴振华 · 869浏览 · 2019-05-09 17:15:04
Facebook 停止屏蔽部分区块链广告

· 754浏览 · 2019-05-09 17:20:08
加载中

0评论

评论
分类专栏
小鸟云服务器
扫码进入手机网页