OCiOS开发:数据持久化之属性列表、归档、NSUserDefaults

应用沙盒简介

1、iOS系统为每个应用程序提供了独立的存储空间“沙盒”。

2、每个应用程序都遵守沙盒机制,即程序仅能访问自身所属沙盒空间内的数据。

3、沙盒为程序主路径,包含以下目录:

  • Document:存储用户自定义数据。

  • Library:存储应用程序相关数据。

  • tmp: 存放临时文件的地方,当iPhone重启时,会丢弃该目录里所有的文件 。

4、路径获取:

  • 获取沙盒主路径:NSHomeDirectory()

  • 获取Document路径:[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]

  • 获取Library路径:[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject]

  • 获取Temp路径:NSTemporaryDirectory( )

  • 获取应用包路径:[[NSBundle mainBundle] pathForAuxiliaryExecutable:@”“]

NSFileManager 文件管理类

1、NSFileManager可以完成沙盒路径下的文件管理工作,包括目录创建、文件创建、删除、移动、复制等。

2、NSFileManager使用单例方法访问:

+ (NSFileManager *)defaultManager;

3、判断指定路径下是否存在文件:

- (BOOL)fileExistsAtPath:(NSString *)path;

- (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory;

4、文件处理方法:

// 1、创建文件
- (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)attr;

// 2、创建目录
- (BOOL)createDirectoryAtPath:(NSString *)path attributes:(NSDictionary *)attributes;

// 3、复制文件
- (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;

// 4、移动文件
- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;

// 5、删除文件
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error;

NSUserDefaults

1、NSUserDefaults 可以让用户对应用程序进行一些简单的配置。

2、NSUserDefaults 同时也是一种轻量的持久化存储机制。

3、NSUserDefaults 使用单例方法访问:

+ (NSUserDefaults *)standardUserDefaults;

4、NSUserDefaults 存储数据:


- (void)setObject:(id)value forKey:(NSString *)defaultName;

- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName;

- (void)setFloat:(float)value forKey:(NSString *)defaultName;

- (void)setDouble:(double)value forKey:(NSString *)defaultName;

- (void)setBool:(BOOL)value forKey:(NSString *)defaultName;

- (void)setURL:(NSURL *)url forKey:(NSString *)defaultName;

5、NSUserDefaults 读取数据:

- (id)objectForKey:(NSString *)defaultName;

- (NSInteger)integerForKey:(NSString *)defaultName;

- (float)floatForKey:(NSString *)defaultName;

- (double)doubleForKey:(NSString *)defaultName;

- (BOOL)boolForKey:(NSString *)defaultName;

- (NSURL *)URLForKey:(NSString *)defaultName;

6、NSUserDefaults 同步数据到文件系统:

- (BOOL)synchronize;

属性列表

1、Cocoa中有一类名为属性列表的文件,简写为plist(Property List)。

2、Cocoa知道如何将此类对象进行保存和加载,即属性列表对象可以直接写入文件,或从文件加载为相应属性列表对象。

3、常见的属性列表数据类型包括:NSString、NSNumber、NSDate、NSData、NSArray、NSDictionary及其变体(NSMutable)。

4、对于集合属性列表类NSArray、NSDictionary需要其内部的对象也是属性列表类,才可以写入文件系统。

5、属性列表类写入文件系统方法:

- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile;

6、Plist文件创建步骤:Command + N -> iOS or OSX -> Resource -> Peoperty List

对象归档

1、系统属性列表类默认可以写入文件,用户自定义类无法写入文件。

2、自定义类的对象可以通过归档来完成写入文件系统。

4、通过遵守NSCoding协议并实现协议方法:

- (void)encodeWithCoder:(NSCoder *)aCoder;

- (id)initWithCoder:(NSCoder *)aDecoder;

5、使用NSKeyedUnarchiver、NSKeyedArchiver将对象归档为NSData写入文件或加载到内存。

数据持久化案例

界面展示

这里写图片描述

代码示例

Plist代码示例
#import "ViewController.h"

/**< 打印路径 */
#define NSLOG_DOCUMENTS_PATH  NSLog(@"%@", NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject);

/**< 沙盒地址 */
#define DOCUMENT_PATH NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject

/**< 文件管理类 */
#define DEFAULT_FILEMANAGER [NSFileManager defaultManager]

static NSString *const PlistName      = @"/UserInfomation.plist";
static NSString *const NameKey        = @"name";
static NSString *const AddressKey     = @"address";
static NSString *const PhoneKey       = @"phone";

@interface ViewController ()

@property (strong, nonatomic) IBOutlet UITextField *nameTextField;
@property (strong, nonatomic) IBOutlet UITextField *addressTextField;
@property (strong, nonatomic) IBOutlet UITextField *phoneTextField;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark *** Plist ***

/**
 * 手动创建Plist文件
 *
 * 1、Command + N -》 ios or OSX -》Resource -》Property List
 * 2、对plist文件数据的操作,如果增加一条数据,key相同则是对原有数据修改
 */


- (IBAction)plist_save:(id)sender {

    if ([self isEmptyData]) {
        NSLog(@"文本信息为空,存储失败!");
        return;
    }

    // 获取plist路径
    NSString *plistPath = [DOCUMENT_PATH stringByAppendingString:PlistName];
    // 初始化根数组
    NSMutableArray *rootArr = nil;
    // 初始化文件管理器
    NSFileManager *fileManager = DEFAULT_FILEMANAGER;
    // 判断沙盒中是否存在属性列表,如果存在,则根据plist文件初始化根字典,如果不存在,则直接初始化根字典;
    if ([fileManager fileExistsAtPath:plistPath]) {
        rootArr = [NSMutableArray arrayWithContentsOfFile:plistPath];
    }else {
        rootArr = [NSMutableArray array];
    }
    // 初始化用户信息字典
    NSMutableDictionary *infoDict = [NSMutableDictionary dictionary];
    // 录入用户信息
    [infoDict setObject:self.nameTextField.text forKey:NameKey];
    [infoDict setObject:self.addressTextField.text forKey:AddressKey];
    [infoDict setObject:self.phoneTextField.text forKey:PhoneKey];

    // 将用户新字典存入数组
    [rootArr addObject:infoDict];
    // 将根输入写入沙盒路径
    if ([rootArr writeToFile:plistPath atomically:YES]) {
        NSLog(@"属性列表添加数据成功!");
    }else {
        NSLog(@"属性列表添加数据失败!");
    }

}
- (IBAction)plist_read:(id)sender {
    NSString *plistPath = [DOCUMENT_PATH stringByAppendingString:PlistName];

    if ([DEFAULT_FILEMANAGER fileExistsAtPath:plistPath]) {
        NSArray *rootArr = [NSArray arrayWithContentsOfFile:plistPath];
        if (rootArr.count > 0) {
            NSLog(@"%@", rootArr);
        }else {
            NSLog(@"属性列表中没有数据!");
        }
    }else {
        NSLog(@"属性列表不存在!");
    }
}
- (IBAction)plist_delete:(id)sender {
    NSString *plistPath = [DOCUMENT_PATH stringByAppendingString:PlistName];
    if ([DEFAULT_FILEMANAGER fileExistsAtPath:plistPath]) {
        NSMutableArray *rootArr = [NSMutableArray arrayWithContentsOfFile:plistPath];
        if (rootArr.count > 0) {
            [rootArr removeAllObjects];
            [rootArr writeToFile:plistPath atomically:YES];
            NSLog(@"属性列表删除数据成功!");
        }else {
            NSLog(@"属性列表中没有数据!");
        }
    }else {
        NSLog(@"属性列表不存在!");
    }
}

#pragma mark *** 异常处理 ***
- (BOOL)isEmptyData {
    // 判断文本是否为空
    if (self.nameTextField.text.length == 0 || self.addressTextField.text.length == 0 || self.phoneTextField.text.length == 0) {
        return YES;
    }else {
        return NO;
    }
}

#pragma mark *** Touches ***
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}


@end
NSUserDefaults代码示例
#import "ViewController.h"

static NSString *const DefaultsKey    = @"data";

static NSString *const NameKey        = @"name";
static NSString *const AddressKey     = @"address";
static NSString *const PhoneKey       = @"phone";


@interface ViewController ()

@property (strong, nonatomic) IBOutlet UITextField *nameTextField;
@property (strong, nonatomic) IBOutlet UITextField *addressTextField;
@property (strong, nonatomic) IBOutlet UITextField *phoneTextField;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark *** NSUserDefaults ***
- (IBAction)defaults_save:(id)sender {
    if ([self isEmptyData]) {
        NSLog(@"文本信息为空,存储失败!");
        return;
    }

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSMutableArray *rootArr = nil;
    if ([defaults objectForKey:DefaultsKey]) {
        rootArr = [NSMutableArray arrayWithArray:[defaults objectForKey:DefaultsKey]];
    }else {
        rootArr = [NSMutableArray array];
    }

    NSDictionary *infoDict = @{NameKey   : self.nameTextField.text,
                               AddressKey: self.addressTextField.text,
                               PhoneKey  : self.phoneTextField.text};
    [rootArr addObject:infoDict];

    [defaults setObject:rootArr forKey:DefaultsKey];
    [defaults synchronize];

    NSLog(@"系统单例存储数据成功!");


}
- (IBAction)defaults_read:(id)sender {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSArray *rootArr = [defaults objectForKey:DefaultsKey];
    if (rootArr && rootArr.count > 0) {
        NSLog(@"%@", rootArr);
    }else {
        NSLog(@"系统单例读取数据失败!");
    }
}
- (IBAction)defaults_delete:(id)sender {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    [defaults removeObjectForKey:DefaultsKey];
    [defaults synchronize];
    NSLog(@"系统单例删除数据成功!");
}


#pragma mark *** 异常处理 ***
- (BOOL)isEmptyData {
    // 判断文本是否为空
    if (self.nameTextField.text.length == 0 || self.addressTextField.text.length == 0 || self.phoneTextField.text.length == 0) {
        return YES;
    }else {
        return NO;
    }
}

#pragma mark *** Touches ***
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}


@end
Archive对象归档代码示例
  • 自定类归档需遵守NSCoding协议,此处对Person类进行归档。

steps 1 -> Person.h文件

#import <Foundation/Foundation.h>

@interface Person : NSObject <NSCoding>

@property (nonatomic, strong)NSString *name;
@property (nonatomic, strong)NSString *address;
@property (nonatomic, strong)NSString *phoneNumber;

- (NSString *)description;

@end

steps 2 -> Person.m文件

#import "Person.h"

@implementation Person

// - 当将一个自定义对象保存到文件的时候就会调用该方法;
// - 在该方法中,说明如何存储自定义对象的属性,也就是说在该方法中说清楚存储自定义对象的哪些属性;

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeObject:self.address forKey:@"address"];
    [aCoder encodeObject:self.phone forKey:@"phone"];
}

// - 当文件中读取一个对象的时候就会调用该方法;
// - 在该方法中说明如何读取保存在文件中的对象,也就是说在该方法中说清楚怎么读取文件中的对象

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.address = [aDecoder decodeObjectForKey:@"address"];
        self.phone = [aDecoder decodeObjectForKey:@"phone"];
    }
    return self;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"\nname = %@\naddress = %@\nphone = %@",
            self.name,
            self.address,
            self.phone];
}
@end

steps 3 -> ViewController.m文件

#import "ViewController.h"
#import "Person.h"

/**< 打印路径 */
#define NSLOG_DOCUMENTS_PATH  NSLog(@"%@", NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject);

/**< 沙盒地址 */
#define DOCUMENT_PATH NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject

/**< 文件管理类 */
#define DEFAULT_FILEMANAGER [NSFileManager defaultManager]

static NSString *const ArchiveName    = @"/PersonInfomation";

@interface ViewController ()

@property (strong, nonatomic) IBOutlet UITextField *nameTextField;
@property (strong, nonatomic) IBOutlet UITextField *addressTextField;
@property (strong, nonatomic) IBOutlet UITextField *phoneTextField;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark *** Archive ***
/**
 *  归档:直接把一个对象弄成一个文件
 *  遵循<NSCoding>的类的对象都可以被归档
 *  自定义类若想归档需遵守<NSCoding>协议
 *  归档方法: + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path;
 *
 */
- (IBAction)archive_save:(id)sender {
    if ([self isEmptyData]) {
        NSLog(@"文本信息为空,存储失败!");
        return;
    }

    // 创建对象
    Person *person = [[Person alloc] init];
    // 对象赋值
    person.name    = self.nameTextField.text;
    person.address = self.addressTextField.text;
    person.phone   = self.phoneTextField.text;

    // 获取归档路径
    NSString *archivePath = [DOCUMENT_PATH stringByAppendingString:ArchiveName];
    // 将自定义对象保存到文件中
    if ([NSKeyedArchiver archiveRootObject:person toFile:archivePath]) {
        NSLog(@"归档数据成功!");
    }else {
        NSLog(@"归档数据失败!");
    }
}
- (IBAction)archive_read:(id)sender {
    NSString *archivePath = [DOCUMENT_PATH stringByAppendingString:ArchiveName];
    Person *person = [NSKeyedUnarchiver unarchiveObjectWithFile:archivePath];
    if (person) {
        NSLog(@"%@", person);
    }else {
        NSLog(@"读取归档数据失败!");
    }
}
- (IBAction)archive_delete:(id)sender {
    NSString *archivePath = [DOCUMENT_PATH stringByAppendingString:ArchiveName];
    if ([DEFAULT_FILEMANAGER fileExistsAtPath:archivePath]) {
        [DEFAULT_FILEMANAGER removeItemAtPath:archivePath error:nil];
        NSLog(@"删除归档成功!");
    }else {
        NSLog(@"归档文件不存在!");
    }
}
#pragma mark *** 异常处理 ***
- (BOOL)isEmptyData {
    // 判断文本是否为空
    if (self.nameTextField.text.length == 0 || self.addressTextField.text.length == 0 || self.phoneTextField.text.length == 0) {
        return YES;
    }else {
        return NO;
    }
}

#pragma mark *** Touches ***
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self.view endEditing:YES];
}


@end
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值