【iOS】—— iOS持久化

1. 数据持久化的目的

  1. 快速展示,提升体验

    • 已经加载过的数据,用户下次查看时,不需要再次从网络(磁盘)加载,直接展示给用户
  2. 节省用户流量(节省服务器资源)

    • 对于较大的资源数据进行缓存,下次展示无需下载消耗流量
    • 同时降低了服务器的访问次数,节约服务器资源。(图片)
  3. 离线使用。

    • 用户浏览过的数据无需联网,可以再次查看。
    • 部分功能使用解除对网络的依赖。(百度离线地图、图书阅读器)
    • 无网络时,允许用户进行操作,等到下次联网时同步到服务端。
  4. 记录用户操作

    • 草稿:对于用户需要花费较大成本进行的操作,对用户的每个步骤进行缓存,用户中断操作后,下次用户操作时直接继续上次的操作。
    • 已读内容标记缓存,帮助用户识别哪些已读。
    • 搜索记录缓存

2. iOS持久化的方案

  • NSUserDefault 简单数据快速读写
  • Property list (属性列表)文件存储
  • Archiver (归档)
  • SQLite 本地数据库
  • CoreData

3. 数据持久化方式的分类

内存缓存

定义:对于使用频率较高的数据,从网络或者磁盘加载数据到内存以后,使用后并不会马上销毁,下次使用直接从内存加载。

内存指当前程序的运行空间,缓存速度快,容量小,是临时存储文件用的。他是在内存中存储,关闭程序后内存就又回到原来的空间

  • 案例:
    • iOS系统图片加载—— [UIImage imageNamed:@“imageName”]
    • 网络图片加载第三方库SDWebImage
磁盘缓存

定义:将从网络加载的,用户操作产生的数据写入到磁盘,用户下次查看、继续操作时,直接从磁盘加载使用。

磁盘是程序的储存空间,缓存容量大,速度慢,可持有化。与内存不同的是磁盘是永久存储东西的。

  • 案例:
    • 用户输入内容草稿缓存
    • 搜索历史缓存
    • 网络图片加载三方库 SDWebImage

4. 沙盒机制

iOS中的沙盒机制是一种安全体系,为了保证系统安全,iOS每个应用程序在安装的时候,会创建属于自己的沙盒文件,应用只能访问自己的沙盒文件,不能访问其他应用的沙盒文件,当应用程序需要向外部请求或接收数据时,都需要经过权限认证,否则,无法获取到数据。所有的非代码文件都要保存在此,例如属性文件plist、文本文件、图像、图标、媒体资源等,其原理是通过重定向技术,把程序生成和修改的文件定向到自身文件夹中。

5. 沙盒的目录结构

获取应用程序的沙盒路径
 NSString *path = NSHomeDirectory();
 NSLog(@"%@", path);

在这里插入图片描述

每次编译代码会生成新的沙盒路径,每次运行获得的沙盒路径都不一样。

在这里插入图片描述

上面的代码得到的是当前程序应用目录的路径,该目录下就是应用程序的沙盒,在该目录下有4个文件夹:DocumentsLibrarySystemDatatmp当前应用程序只能访问该目录下的文件。

  1. Documents 目录:您应该将所有的应用程序数据文件写入到这个目录下。这个目录用于存储用户数据。该路径可通过配置实现iTunes共享文件。可被iTunes备份。
  2. AppName.app 目录:这是应用程序的程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动。
  3. Library 目录:这个目录下有两个子目录:
    • Preferences 目录:包含应用程序的偏好设置文件。您不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好。
    • Caches 目录:用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息。
  4. tmp 目录:这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息。该路径下的文件不会被iTunes备份。
访问沙盒目录常用C函数介绍
 //文件路径搜索
FOUNDATION_EXPORT NSArray<NSString *> *NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde);

该方法返回值为一个数组,在iphone中由于只有一个唯一路径,所以直接取数组第一个元素即可。

  • 参数一 NSSearchPathDirectory directory:指定搜索的目录名称,比如这里用NSDocumentDirectory表明我们要搜索的是Documents目录。如果我们将其换成NSCachesDirectory就表示我们搜索的是Library/Caches目录。
  • 参数二 NSSearchPathDomainMask domainMask:搜索主目录的位置,NSUserDomainMask表示搜索的范围限制于当前应用的沙盒目录。还可以写成NSLocalDomainMask(表示/Library)、NSNetworkDomainMask(表示/Network)等。
  • 参数三 BOOL expandTilde:是否获取完整的路径,我们知道在iOS中的全写形式是/User/userName,该值为YES即表示写成全写形式,为NO就表示直接写成“~”。
 typedef NS_OPTIONS(NSUInteger, NSSearchPathDomainMask) {
    NSUserDomainMask = 1,       // 用户目录 - 基本上就用这个。 
    NSLocalDomainMask = 2,      // 本地
    NSNetworkDomainMask = 4,    // 网络 
    NSSystemDomainMask = 8,     // 系统
    NSAllDomainsMask = 0x0ffff  // 所有 
};

//常用的NSSearchPathDirectory枚举值
typedef NS_ENUM(NSUInteger, NSSearchPathDirectory) {
    NSApplicationDirectory = 1,             // supported applications (Applications)
    NSDemoApplicationDirectory,             // unsupported applications, demonstration versions (Demos)
    NSAdminApplicationDirectory,            // system and network administration applications (Administration)
    NSLibraryDirectory,                     // various documentation, support, and configuration files, resources (Library)
    NSUserDirectory,                        // user home directories (Users)
    NSDocumentationDirectory,               //  Library 下的(Documentation)模拟器上没有创建
    NSDocumentDirectory,                    // documents (Documents)
};

在这里插入图片描述

沙盒目录介绍
  • Documents:保存持久化数据,会备份。一般用来存储需要持久化的数据。
    一般我们在项目中,我们会把一些用户的登录信息以及搜索历史记录等一些关键数据存储到这里。
 NSString *documentfileName = [documentDirectory stringByAppendingPathComponent:@"data.txt"];
 NSLog(@"%@", documentfileName);

这样这个filename就是完整的.txt文件的目录。

  • Library:默认存放设置和其他状态,除了cache子目录之外都会被iCloud同步。

    • Application Support:包含程序用来运行但应对用户隐藏的文件。
    • Caches:保存应用运行时生成的需要持久化的数据,一般存储体积大、不需要备份的非重要数据,如网络请求的音视频与图片等的缓存。
    • Cookies:系统会将App中的网络请求cookies保存为文件。
    • Preferences:保存应用的所有偏好设置,UserDefaults生成的plist文件保存到该目录下。
    • SplashBoard:存储启动屏缓存,缓存文件格式为 ktx,本质上就是图片,如果启动屏不生效的问题可以考虑从删除该路径下相关缓存文件这个角度解决。
  • SystemData:存放系统数据,无对外暴露的接口。

  • tmp:临时文件夹(系统会不定期删除里面的文件)。

6. 持久化的存储方式

XML属性列表

属性列表是一种XML格式的文件,拓展名为plist

如果对象是NSStringNSDictionaryNSArrayNSDataNSNumber等类型,就可以使用
writeToFile:atomically:方法直接将对象写到属性列表文件中,举例说明:

 //获取文件目录
    NSArray<NSString*> *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentDirectory = [document firstObject];
    NSLog(@"documentDirectory:%@", documentDirectory);
    NSString *documentfileName = [documentDirectory stringByAppendingPathComponent:@"data.txt"];
    NSLog(@"%@", documentfileName);
    //存字典   将字典数据存储到plist文件
    NSDictionary *dict = @{@"name": @"cuiyang", @"boom": @"9527"};
    [dict writeToFile:documentfileName atomically:YES];
    
    //取字典
    NSDictionary *msgDict = [NSDictionary dictionaryWithContentsOfFile:documentfileName];
    NSLog(@"%@", msgDict);

在这里插入图片描述

进入该项目的沙盒目录,可以看到Document目录下多了我们建立的test.plist文件。
在这里插入图片描述

能看到我们存储的字典类型的文件已经存放:
在这里插入图片描述

Preference 偏好设置(UserDefaults)

很多iOS应用都支持偏好设置,提供了一套标准的解决方案来为应用加入偏好设置功能,比如保存用户名,字体大小,密码,是否自动登录等。

每个应用都有个NSUserDefaults实例,可以通过它来存取偏好设置,不需要路径。其本身的创建类似于单例模式,我们在后面用不同的属性名再次申请创建,会覆盖之前的数据。

NSUserDefaults:简单数据快速读写,不能存储自定义类型。
UserDefaults设置数据时,不是立即写入,而是根据时间戳定时地把缓存中的数据写入本地磁盘。所以调用了set方法之后数据有可能还没有写入磁盘应用程序就终止了。出现以上问题,可以通过调用synchornize方法[defaults synchornize];强制写入。

偏好设置存储的优点

  • 不需要关心文件名,系统会自动帮你生成一个文件名。
  • 快速做键值对的存储。
 - (void)preference {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // 存储数据,快速键值对/
    [defaults setObject:@"hanjiawei" forKey:@"username"];
    [defaults setObject:@"9527-2004" forKey:@"password"];
    
    [defaults synchronize];
    
    // 需要验证账号密码的地方,获取偏好设置对象
    NSUserDefaults *defaultsA = [NSUserDefaults standardUserDefaults];
    NSString *name = [defaultsA objectForKey:@"username"];
    NSString *password = [defaultsA objectForKey:@"password"];
    NSLog(@"name:%@ password:%@", name, password);
    
}

在这里插入图片描述

NSKeyedArchiver归档解档

NSKeyedArchiver(归档):归档一般都是保存自定义对象的时候,使用归档。因为plist文件不能够保存自定义对象。如果一个字典中保存有自定义对象,如果把这个对象写入到文件当中,就不会生成plist文件。如果对象是NSStringNSDictionaryNSArrayNSDataNSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复。

在使用解档和归档的时候,必须遵守NSSecureCoding协议才行,但是新版本就必须的遵守NSSecureCoding协议,NSSecureCoding协议也遵循了原来NSCoding这个协议,不过我们还需要遵循它的一个supportsSecureCoding方法,这样我们才能归档成功。

因为NSSecureCoding协议也遵循了原来NSCoding这个协议,所以他也就有了- (void)encodeWithCoder:(NSCoder *)coder方法和- (id)initWithCoder:(NSCoder *)coder方法:

  1. - (void)encodeWithCoder:(NSCoder *)coder方法:每次归档对象,都调用这个方法。在这个方法里面指定如何归档对象中的每个实例变量。可以使用encodeObject:forKey:方法归档实例变量。
  2. - (id)initWithCoder:(NSCoder *)coder方法:每次从文件中恢复对象的时候,都会调用这个方法,在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量。

除了这两个方法之外,NSSecureCoding协议还有**+ (BOOL)supportsSecureCoding方法**,只有当这个方法为YES的时候,才可以归档成功。

利用归档解档尝试存储一个Person对象

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject<NSSecureCoding>
@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) int age;

- (void)saveData;
- (void)readData;

@end

NS_ASSUME_NONNULL_END

 
#import "Person.h"
@implementation Person

- (void)encodeWithCoder:(nonnull NSCoder *)coder {
    [coder encodeObject:_name forKey:@"name"];
    [coder encodeInt:_age forKey:@"age"];
}

- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
    if (self = [super init]) {
        _name = [coder decodeObjectForKey:@"name"];
        _age = [coder decodeIntForKey:@"age"];
    }
    return self;
}
// 返回YES才能成功归档
+ (BOOL)supportsSecureCoding {
    return YES;
}

- (void)saveData {
    Person *p = [[Person alloc] init];
    p.name = @"hanjiawei";
    p.age = 20;
    NSError *error;
    // 2.归档模型对象
    // 3.获得 Documents 的全路径
    NSString *docu = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    // 4.获得新文件的全路径,即新建一个 person.data 文件来存储我们要归档的数据
    NSString *path = [docu stringByAppendingString:@"/person.plist"];
    NSLog(@"%@", path);
    // 5.将对象封装为 Data 数据并归档
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:p requiringSecureCoding:YES error:&error];
    if (error) {
        NSLog(@"sodufosuf%@", error);
    }
    [data writeToFile:path atomically:YES];
    
}

// 读档,将数据从文件中读出
- (void)readData {
   NSError *error;
   // 1.获得 Documents 的全路径
   NSString *docu = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
   // 2.获得文件的全路径,即获取我们要解档文件的路径
   NSString *path = [docu stringByAppendingString:@"/person.plist"];
   // 3.从 path 路径中获取 Data 数据
   NSData *unData = [NSData dataWithContentsOfFile:path];
   // 4.从文件中读取Person对象
   Person *person = (Person *)[NSKeyedUnarchiver unarchivedObjectOfClass:[Person class] fromData:unData error:&error];
   // 打印结果
   NSLog(@"name: %@ age: %d",person.name, person.age);
}


@end


Document多了一个plist文件
在这里插入图片描述

我们一定要遵守NSSecureCoding协议,并实现它的归档解档方法,以及+ (BOOL)supportsSecureCoding方法!!!

数据库存储
  • SQLite:
    是目前主流的嵌入式关系型数据库,其最主要的特点就是轻量级、跨平台,当前很多嵌入式操作系统都将其作为数据库首选。

  • CoreData:
    CoreData是iOS5之后才出现的一个框架,本质上是对SQLite的一个封装,它提供了对象-关系映射(ORM)的功能,即能够将OC对象转化成数据,保存在SQLite数据库文件中,也能够将保存在数据库中的数据还原成OC对象,在这个过程中不需要手动编写任何SQL语句,CoreData封装了数据库的操作过程,以及数据库中数据和OC对象的转换过程。通过CoreData管理应用程序的数据模型,可以极大程度减少需要编写的代码数量。

  • FMDB:

    是一个处理数据存储的第三方框架,框架是对sqlite的封装,整个框架非常轻量级但又不失灵活性,而且更加面向对象。

SQLite和CoreData的区别:

  • CoreData可以在一个对象更新时,其关联的对象也会随着更新,相当于你更新一张表时,其关联的其他表的也会随着更新。
  • CoreData供更简单的性能管理机制,可以限制查询记录的总数,这个类会自动更新其缓存。
  • 多表查询方面,CoreData没有SQL直观,没有类似外连接,左连接等操作。
什么是序列化和反序列化? 用来做什么?
  • 序列化:把对象转化为字节序列的过程
  • 反序列化:把字节序列恢复成对象
  • 作用:把对象写到文件或者数据库中,并且读取出来

iOS中怎么实现序列化?

在iOS实际开发中,我们也会使用到序列化,归档就是我们在iOS开发中使用序列化的场景!
在iOS中一个自定义对象是无法直接存入到文件中的,必须先转化成二进制流才行。从对象到二进制数据的过程我们一般称为对象的序列化(Serialization),也称为归档(Archive)。同理,从二进制数据到对象的过程一般称为反序列化或者反归档(解档)。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在MATLAB中,NURBS(非均匀有理B样条)是一种强大的数学工具,用于表示和处理复杂的曲线和曲面。NURBS在计算机图形学、CAD(计算机辅助设计)、CAM(计算机辅助制造)等领域有着广泛的应用。下面将详细探讨MATLAB中NURBS的绘制方法以及相关知识点。 我们需要理解NURBS的基本概念。NURBS是B样条(B-Spline)的一种扩展,其特殊之处在于引入了权重因子,使得曲线和曲面可以在不均匀的参数空间中进行平滑插值。这种灵活性使得NURBS在处理非均匀数据时尤为有效。 在MATLAB中,可以使用`nurbs`函数创建NURBS对象,它接受控制点、权值、 knot向量等参数。控制点定义了NURBS曲线的基本形状,而knot向量决定了曲线的平滑度和分布。权值则影响曲线通过控制点的方式,大的权值会使曲线更靠近该点。 例如,我们可以使用以下代码创建一个简单的NURBS曲线: ```matlab % 定义控制点 controlPoints = [1 1; 2 2; 3 1; 4 2]; % 定义knot向量 knotVector = [0 0 0 1 1 1]; % 定义权值(默认为1,如果未指定) weights = ones(size(controlPoints,1),1); % 创建NURBS对象 nurbsObj = nurbs(controlPoints, weights, knotVector); ``` 然后,我们可以用`plot`函数来绘制NURBS曲线: ```matlab plot(nurbsObj); grid on; ``` `data_example.mat`可能包含了一个示例的NURBS数据集,其中可能包含了控制点坐标、权值和knot向量。我们可以通过加载这个数据文件来进一步研究NURBS的绘制: ```matlab load('data_example.mat'); % 加载数据 nurbsData = struct2cell(data_example); % 转换为cell数组 % 解析数据 controlPoints = nurbsData{1}; weights = nurbsData{2}; knotVector = nurbsData{3}; % 创建并绘制NURBS曲线 nurbsObj = nurbs(controlPoints, weights, knotVector); plot(nurbsObj); grid on; ``` MATLAB还提供了其他与NURBS相关的函数,如`evalnurbs`用于评估NURBS曲线上的点,`isoparm`用于生成NURBS曲面上的等参线,以及`isocurve`用于在NURBS曲面上提取特定参数值的曲线。这些工具对于分析和操作NURBS对象非常有用。 MATLAB中的NURBS功能允许用户方便地创建、编辑和可视化复杂的曲线和曲面。通过对控制点、knot向量和权值的调整,可以精确地控制NURBS的形状和行为,从而满足各种工程和设计需求。通过深入理解和熟练掌握这些工具,可以在MATLAB环境中实现高效的NURBS建模和分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值