iOS本地数据存储

2018-08-30  本文已影响0人  Relax_lady

iOS应用数据存储的常用方式

XML属性列表(plist)归档
Preference(偏好设置)
NSKeyedArchiver归档 / NSKeyedUnarchiver解档
SQLite3
FMDB
Core Data

1、沙盒

沙盒也叫沙箱,英文standbox,其原理是通过重定向技术,把程序生成和修改的文件定向到自身文件夹中。在沙盒机制下,每个程序之间的文件夹不能互相访问。iOS系统为了保证系统安全,采用了这种机制

iOS 应用程序在安装时,会创建属于自己的沙盒文件,应用程序不能直接访问其他应用程序的沙盒文件,当应用程序需要向外部请求或接收数据时,都需要经过权限认证,否则,无法获取到数据。

应用程序中所有的非代码文件都保存在沙盒中,比如图片、声音、属性列表,sqlite数据库和文本文件等。


app沙盒目录结构

沙盒的的根目录有三个文件夹,分别是 Documents,Library,tmp


沙盒根目录
如何获取到对应目录下的路径?
// home
NSString *home = NSHomeDirectory();

// Documents
NSString *docDir1 = [NSString stringWithFormat:@"%@/%@",home,@"Documents"];

NSString *docDir2 = [home stringByAppendingPathComponent:@"Documents"];

NSString *docDir3 = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

// Library/Caches
NSString *cacheDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// Library/Preferences
NSString *preferencesDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"Preferences"];
// tmp
NSString *tempDir = NSTemporaryDirectory();

2、plist

plist是一种明文的轻量级存储方式,这种方式的安全性几乎为0.

/**
 *  Plist文件
 */

- (void)setUpPlist {

    NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [path stringByAppendingPathComponent:@"Person.plist"];
    
    NSDictionary *dict = @{
                           @"name" : @"William",
                           @"age" : @18,
                           @"height" : @1.75f
                           };
    
    // 将数据写入Plist
    [dict writeToFile:filePath atomically:YES];
    NSLog(@"%@", filePath);
    
    // 读取plist中的数据
    NSDictionary *dicts = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"dict = %@",dicts);
    NSString *str = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"str = %@", str);
}
plist日志.png plist.png

3、Preference(偏好设置)

偏好设置的使用非常方便快捷,我们一般使用它来进行一些设置的记录,比如用户名,开关是否打开等设置。
Preference是通过NSUserDefaults来使用的,是通过键值对的方式记录设置

重点说明:

(1)偏好设置是专门用来保存应用程序的配置信息的, 一般情况不要在偏好设置中保存其他数据。如果利用系统的偏好设置来存储数据, 默认就是存储在Preferences文件夹下面的,偏好设置会将所有的数据都保存到同一个文件中。
(2)使用偏好设置对数据进行保存之后, 它保存到系统的时间是不确定的,会在将来某一时间点自动将数据保存到Preferences文件夹下面,如果需要即刻将数据存储,可以使用[defaults synchronize];
(3)注意点:所有的信息都写在一个文件中,对比简单的plist可以保存和读取基本的数据类型。
(4)步骤:获取NSuserDefaults,保存(读取)数据
(5)NSUserDefaults可以存储的数据类型包括:NSData、NSString、NSNumber、NSDate、NSArray、NSDictionary。如果要存储其他类型,则需要转换为前面的类型,才能用NSUserDefaults存储。

/**
 *  偏好设置
 */
// 不能保存自定义的对象
- (void)setUpSaveUserDefaults {

    // 获取NSUsersDefault对象(是个单利)
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSLog(@"%@", defaults);
    // 保存数据(注意: 如果设置的数据没有同步, 那么会在将来的某个时刻自动将数据保存到Preference文件夹下面)
    [defaults setObject:@"Mr.William" forKey:@"name"];
    [defaults setInteger:23 forKey:@"age"];
    [defaults setDouble:1.75f forKey:@"height"];
    [defaults setObject:@"man" forKey:@"gender"];
    
    // 强制让数据立刻保存
    [defaults synchronize];
}
Preference存储.png
// 读取数据
- (void)setUpReadUserDefaults {

    // 同样获取NSUserDefault对像
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    
    // 读取数据
    NSString *name = [defaults objectForKey:@"name"];
    NSString *gender = [defaults objectForKey:@"gender"];
    NSInteger age = [defaults integerForKey:@"age"];
    double height = [defaults doubleForKey:@"height"];
    
    NSLog(@"name=%@,gender=%@,age=%ld,height=%.1f",name,gender,age,height);
}
Preference读取.png

4、NSKeyedArchiver归档 / NSKeyedUnarchiver解档

归档和解档会在写入、读出数据之前进行序列化、反序列化,数据的安全性相对高一些。

序列化与反序列化:

序列化: 将一个OC对象转换成NSData(二进制)的操作就叫做对象的序列化
反序列化: 将本地的二进制数据转为一个OC对象的操作就叫做反序列化

OC对象需要通过遵守NSCoding协议,并且实现协议中的两个方法,才能支持序列化和反序列化操作.

#import <Foundation/Foundation.h>

@class Person;

@interface ArchiverManager : NSObject


+ (instancetype)sharedInstance;

/**
 运用NSKeyedArchiver归档数据
 **/
- (BOOL)writePersonData:(Person *)person;

/**
 使用NSKeyedUnarchiver解档数据
 **/

- (Person *)readPersonData;

/**
 清除数据
 **/

- (BOOL)cleanData;
    
@end

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, assign) NSInteger age;

@end
#import "ArchiverManager.h"

@implementation ArchiverManager

+ (instancetype)sharedInstance
{
    static ArchiverManager *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [self new];
    });
    return sharedInstance;
}

/**
 运用NSKeyedArchiver归档数据
 **/
- (BOOL)writePersonData:(Person *)person
{
    NSString *path = [self fullPath];
    NSFileManager *manager = [NSFileManager defaultManager];
    BOOL remove  = [manager removeItemAtPath:path error:nil];
    if (remove)
    {
        NSLog(@"删除成功");
    }
    return [NSKeyedArchiver archiveRootObject:person toFile:path];
}

/**
 使用NSKeyedUnarchiver解档数据
 **/

- (Person *)readPersonData
{
    NSString *path = [self fullPath];
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:path])
    {
        Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
        return person;
    }
    return nil;
}

/**
 清除数据
 **/

- (BOOL)cleanData
{
    NSString *path = [self fullPath];
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:path])
    {
        return [fm removeItemAtPath:path error:nil];
    }
    
    return NO;
}

- (NSString *)fullPath
{
    NSString *docPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject;
    NSString *path=[docPath stringByAppendingPathComponent:@"Person.data"];
    return path;
}

@end


@implementation Person

//归档
- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.name forKey:@"name"];
    [encoder encodeInteger:self.age forKey:@"age"];
}

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

具体使用

/**
 *  归档
 */

- (void)archiverData
{
    //创建Person对象
    Person *person = [Person new];
    person.name = @"relax";
    person.age = 18;
    
    [[ArchiverManager sharedInstance] writePersonData:person];
    
}

/**
 *  解档
 */

- (void)unarchiverData
{
    Person *person = [[ArchiverManager sharedInstance] readPersonData];
    NSLog(@"name=%@,age=%ld,",person.name,person.age);
}
NSKeyedArchiver.png image.png

5、SQLite3

SQLite 不区分大小写,但也有需要注意的地方,例如GLOB 和 glob 具有不同作用。

SQLite3是无类型的,在创建的时候你可以不声明字段的类型,不过还是建议加上数据类型

上一篇 下一篇

猜你喜欢

热点阅读