GeekBand~iOS~开发高级进阶~第四周

数据存储--简易数据存储

数据持久化

1.本地:文件 NSHomeDirectory() / Documents;数据库
2.云端:iCloud (文件,Key-Value数据库);第三方

NSData

Cocoa提供用来表示通用数据:
读、写、访问

图片

->创建 UIImage 对象
-->文件 - bundle
-->NSData
-->CGContext
- CGImageRef CGBitmapContextCreateImage(ctx);

->保存 UIImage 对象
-->via data
- NSData * UIImagePNGRepresentation (UIImage *image);
- NSData * UIImageJPEGRepresentation (UIImage *image, CGFloat compressionQuality);

NSString 与存储

->文本读写
->文件路径处理

Key Value数据

->读

+(NSDictionary<KeyType, ObjectType> *) dictionaryWithContentsOfFile:(NSString *)
+ (NSDictionary<KeyType, ObjectType> *) dictionaryWithContentsOfURL:(NSURL *)

->写

- (BOOL)writeToFile:(NSString *) atomically:(BOOL)
- (BOOL)writeToURL:(NSURL *) atomically:(BOOL)
配置参数

->用来保存默认值
-->经常变的用自己的UI,不常改的放 settings bundle
-->Domian:

- NSArgumentDomain:Xcode.app/Contents/MacOSX/Xcode -IndexOnOpen NO
- Application:NSUserDefaults
- NSGlobalDomain:defaults read NSGlobalDomain
- Languages:AppleLanguage指定用户使用的语言
- NSRegistrationDomain:[NSUserDefaults registerDefaults:]提供的默认值

->Mac OS X的defaults命令

defaults read <domain>[key]
defaults find Xcode.IDE
NSUserDefaults

->访问

[NSUserDefaults standardUserDefaults]  //本地
[NSUbiquitousKeyValueStore defaultStore]  //iCloud

->登记默认值

- [NSUserDefaults registerDefaults:dict];

->访问
读:

-<type>ValueForKey:

写:

-set<Type>:forKey:
Settings Bundle

->Settings.bundle in app root
->Access via standardDefaults

沙盒、文件与对象归档

沙盒机制(SandBox)是一种安全体系,它规定了应用程序只能在为该应用创建的文件夹内读取文件,不可以访问其他地方的内容。所有的非代码文件都保存在这个地方,比如图片、声音、属性列表和文本文件等。
1.每个应用程序都在自己的沙盒内
2.不能随意跨越自己的沙盒去访问别的应用程序沙盒的内容
3.应用程序向外请求或接收数据都需要经过权限认证


沙盒目录.png

MyApp.app
①存放内容
该目录包含了应用程序本身的数据,包括资源文件和可执行文件等。程序启动以后,会根据需要从该目录中动态加载代码或资源到内存,这里用到了lazy loading的思想。
②整个目录是只读的
为了防止被篡改,应用在安装的时候会将该目录签名。非越狱情况下,该目录中内容是无法更改的;在越狱设备上如果更改了目录内容,对应的签名就会被改变,这种情况下苹果官网描述的后果是应用程序将无法启动,我没实践过。
③是否会被iTunes同步

Documents
①存放内容
我们可以将应用程序的数据文件保存在该目录下。不过这些数据类型仅限于不可再生的数据,可再生的数据文件应该存放在Library/Cache目录下。
②是否会被iTunes同步

Documents/Inbox
①存放内容
该目录用来保存由外部应用请求当前应用程序打开的文件。
比如我们的应用叫A,向系统注册了几种可打开的文件格式,B应用有一个A支持的格式的文件F,并且申请调用A打开F。由于F当前是在B应用的沙盒中,我们知道,沙盒机制是不允许A访问B沙盒中的文件,因此苹果的解决方案是讲F拷贝一份到A应用的Documents/Inbox目录下,再让A打开F。
②是否会被iTunes同步

Library
①存放内容
苹果建议用来存放默认设置或其它状态信息。
②是否会被iTunes同步
是,但是要除了Caches子目录外
Library/Caches
①存放内容
主要是缓存文件,用户使用过程中缓存都可以保存在这个目录中。前面说过,Documents目录用于保存不可再生的文件,那么这个目录就用于保存那些可再生的文件,比如网络请求的数据。鉴于此,应用程序通常还需要负责删除这些文件。
②是否会被iTunes同步
否。
Library/Preferences
①存放内容
应用程序的偏好设置文件。我们使用NSUserDefaults写的设置数据都会保存到该目录下的一个plist文件中,这就是所谓的写道plist中!
②是否会被iTunes同步

tmp
①存放内容
各种临时文件,保存应用再次启动时不需要的文件。而且,当应用不再需要这些文件时应该主动将其删除,因为该目录下的东西随时有可能被系统清理掉,目前已知的一种可能清理的原因是系统磁盘存储空间不足的时候。
②是否会被iTunes同步

获取主要目录路径方式:
1.沙盒
NSLog(@"%@",NSHomeDirectory());
2.tmp
NSLog(@"%@",NSTemporaryDirectory());
3.Myapp.app
NSLog(@"%@",[[NSBundle mainBundle] bundlePath]);
4.Documents

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);  
NSString *path = [paths objectAtIndex:0];  
NSLog(@"%@",path); 
iTunes File Sharing

Info.plist
<key>UIFileSharingEnabled</key>

应用间共享文件

->用户授权 + 操作系统代为操作
-->本机 “Open in”
- UIDocumentInteractionController
-->iCloud
- UIDocumentPickerViewController

对象归档

encoder,decoder
NSEncoding protocol
1.保存数据过程

//1.创建对象
    YYstudent *s=[[YYstudent alloc]init];
    s.name=@"wendingding";
    s.age=23;
    s.height=1.7;
    s.weight=62;
    
    //2.获取文件路径
    NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    NSString *path=[docPath stringByAppendingPathComponent:@"person.yangyang"];
    NSLog(@"path=%@",path);
    
    //3.将自定义的对象保存到文件中
     [NSKeyedArchiver archiveRootObject:s toFile:path];

2.读取数据过程

//1.获取文件路径
    NSString *docPath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    NSString *path=[docPath stringByAppendingPathComponent:@"person.yangyang"];
    //2.从文件中读取对象
    YYstudent *s=[NSKeyedUnarchiver unarchiveObjectWithFile:path];

3.遵守NSCoding协议,并实现该协议中的两个方法。
4.如果是继承,则子类一定要重写那两个方法。因为person的子类在存取的时候,会去子类中去找调用的方法,没找到那么它就去父类中找,所以最后保存和读取的时候新增加的属性会被忽略。需要先调用父类的方法,先初始化父类的,再初始化子类的。
5.保存数据的文件的后缀名可以随意命名。
6.通过plist保存的数据是直接显示的,不安全。通过归档方法保存的数据在文件中打开是乱码的,安全。

SQLite3

SQLite是一款轻型的嵌入式数据库,安卓和ios开发使用的都是SQLite数据库。3是版本号,是SQLite的第三个版本。
特点:
1)它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了
2)它的处理速度比Mysql、PostgreSQL这两款著名的数据库都还快
数据库存储数据的步骤
1、新建一个数据库
2、新建一张表(table)
3、添加多个字段(column,列,属性)
4、添加多行记录(row,每行存放多个字段对应的值)
数据操作语句(DML:Data Manipulation Language) 包括insert、update、delete等操作 上面的3种操作分别用于添加、修改、删除表中的数据。
数据查询语句(DQL:Data Query Language) 可以用于查询获得表中的数据 关键字select是DQL(也是所有SQL)用得最多的操作 其他DQL常用的关键字有where,order by,group by和having。
SQLite的字段类型 integer : 整型值 real : 浮点值 text : 文本字符串 blob : 二进制数据(比如文件) 实际上SQLite是无类型的,但为了保持良好的编程规范,方便程序员之间的交流,编写建表语句的时候最好还是加上每个字段的具体类型。

在iOS中使用 SQLite

->链接 libSQLite3.dylib和导入头文件#import
->使用SQLite3函数
-->打开/新建数据库文件

// 拼接数据库地址
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    NSString *sqlFile = [path stringByAppendingPathComponent:@student.sqlite];

// 打开数据
    int result = sqlite3_open(sqlFile.UTF8String, &_db);
// 判断是否打开成功
    if (result == SQLITE_OK) {
        NSLog(@打开成功);
        // 创建表
        /*
         第一个参数: 需要执行SQL语句的数据库对象
         第二个参数: 需要执行的SQL语句
         第三个参数: 回调函数
         第四个参数: 第三个参数的参数
         第五个参数: 接收错误信息
         */
                    // 创建表的sql语句
        NSString *sql = @CREATE TABLE IF NOT EXISTS t_student(id INTEGER PRIMARY KEY AUTOINCREMENT , name TEXT, age INTEGER, score REAL);;
        result = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
        if (result == SQLITE_OK) {
            NSLog(@创建表成功);
        }else
        {
            NSLog(@创建表失败);
        }
    }else
    {
        NSLog(@打开失败);
    }

-->执行SQL命令
2、插入数据

    NSString *sql = @INSERT INTO t_student(age, score, name) VALUES ('28', 100, 'leo');;
    int result =  sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
    if (result == SQLITE_OK) {
        NSLog(@插入成功);
    }

3、修改数据

    NSString *sql = @UPDATE t_student SET name = 'txt';;
    int result =  sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
    if (result == SQLITE_OK) {
        NSLog(@修改成功);
    }

4、删除数据

    NSString *sql = @DELETE FROM t_student WHERE id = 1; ;
    int result =  sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
    if (result == SQLITE_OK) {
        NSLog(@删除成功);
    }

5、查询数据

    NSString *sql = @SELECT * FROM t_student;;
    sqlite3_stmt *stemt = NULL;
    /*
     第一个参数:需要执行SQL语句的数据库
     第二个参数:需要执行的SQL语句
     第三个参数: 告诉系统SQL语句的长度, 如果传入一个小于0的数, 系统会自动计算
     第四个参数:结果集, 里面存放所有查询到的数据
     */
    sqlite3_prepare_v2(_db, sql.UTF8String, -1, &stemt, NULL);
    // 判断有没有查询结果
    while (sqlite3_step(stemt) == SQLITE_ROW) {
        // 取出第一个字段的查询得结果
        const unsigned char *name = sqlite3_column_text(stemt, 1);
        // 取出第一个字段的查询得结果
        int age = sqlite3_column_int(stemt, 2);
        // 取出第一个字段的查询得结果
        double score = sqlite3_column_double(stemt, 3);
        NSLog(@%s %d %f, name, age, score);
    }

-->关闭数据库
sqlite3_close(database);

Core Data

Apple提供的对象持久化框架。使用数据库作为底层存储,也可以使用XML文件。
CoreData中有这么几个常用的元素:

名称                       作用
NSManagedObjectModel        对象模型,指定所用对象文件
NSPersistentStoreCoordinator    持久化存储协调器,设置对象的存储方式和数据存放位置
NSManagedObjectContext    对象管理上下文,负责数据的实际操作(重要)
NSEntityDescriptor        实体描述符,描述一个实体,可以用来生成实体对应的对象
NSManagedObject          对象
NSFetchRequest            对象查询,相当于SQL的Select语句

使用步骤

在创建项目的时候,勾选“Core Data”选项。Xcode会自动替我们
在“AppDelegate”中加入创
建“NSManagedObjectModel”、“NSPersistentStoreCoordinator”和“
NSManagedObjectContext”等对象,方便后面的使用。
1.创建"NSManagedObjectModel"对象

- (NSManagedObjectModel *)managedObjectModel {
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }

    //CoreData模型文件的路径,注意编译好的模型文件名扩展名为"momd"
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreData01" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

2.创建"NSPersistentStoreCoordinator"对象

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    //指定需要持久化的模型对象
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    //持久化的存储文件
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData01.sqlite"];
    NSError *error = nil;
    //设置存储格式为SQLite
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {

    }

    return _persistentStoreCoordinator;
}

3.创建上下文

- (NSManagedObjectContext *)managedObjectContext {
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (!coordinator) {
        return nil;
    }

    //创建管理上下文
    _managedObjectContext = [[NSManagedObjectContext alloc] init];
    //关联上下文与存储对象
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    return _managedObjectContext;
}

4 . 设置模型文件,添加实体(Entity)
点击“CoreData01.xcdatamodelId”文件,然后添加一个实体“Student”,并增加几个属性。Core Data中的实体类似于数据库的表定义,规定了不同字段(属性)的名字和类型。
5 . 创建模型对象的类, "Editor > Create NSManagedobject Subclass"。
6 . 选择使用标量定义数值类型的属性(默认使用NSNumber类型定义int、float等类型的属性)。
7 . Xcode自动创建于实体同名的类,并且继承自“NSManagedObject”。
8 . 创建对象并存储。

//获取AppDelegate中创建的上下文对象
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

NSManagedObjectContext *context = appDelegate.managedObjectContext;

//获取实体描述符
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:context];
//创建对象
Student *student = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:context];
//设置对象的属性
student.name = @"张三";
//保存数据
[context save:nil];

9 . 可以通过"NSFetchRequest"从文件中获取数据。

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSManagedObjectContext *context = appDelegate.managedObjectContext;

//创建请求对象,用于获取实体Student所对应的全部数据,可以通过给NSFetchRequest设置predicate和sortDescriptors对结果进行筛选和排序。
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Student"];
NSArray *result = [context executeFetchRequest:fetchRequest error:nil];
NSLog(@"%@", result);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容