iOS中四种最常用的将数据持久存储在iOS文件系统的机制

前三种机制的相同点都是需要找到沙盒里面的Documents的目录路径,附加自己相应的文件名字符串来生成需要的完整路径,再往里面创建、读取、写入文件

而第四种则是与委托有关,下面给出代码(有修改过的部分)。

这里做的示例是用四个TextField来显示内容,如图

一、属性列表(.plist)

//
//  ViewController.m
//  Persistence
//
//  Created by Kim Topley on 7/31/14.
//  Copyright (c) 2014 Apress. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@property (strong, nonatomic) IBOutletCollection(UITextField) NSArray *lineFields;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSString *filePath = [self dataFilePath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
        ; i < ; i++) {
            UITextField *theField = self.lineFields[i];
            theField.text = array[i];
        }
    }

    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter]
        addObserver:self
        selector:@selector(applicationWillResignActive:)
        name:UIApplicationWillResignActiveNotification
        object:app];
}

- (void)applicationWillResignActive:(NSNotification *)notification {
    NSString *filePath = [self dataFilePath];
    NSArray *array = [self.lineFields valueForKey:@"text"];
    [array writeToFile:filePath atomically:YES];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (NSString *)dataFilePath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(
               NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:];
    return [documentsDirectory stringByAppendingPathComponent:@"data.plist"];
}
@end

ViewController.m

二、对象归档

1、遵循NSCoding协议

2、遵循NSCopying协议

3、对数据对象进行归档和取消归档

//
//  FourLines.h
//  Persistence
//
//  Created by  Jierism on 16/7/27.
//  Copyright © 2016年  Jierism. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface FourLines : NSObject<NSCoding,NSCopying>

@property(copy,nonatomic)NSArray *lines;

@end

FourLines.h

//
//  FourLines.m
//  Persistence
//
//  Created by  Jierism on 16/7/27.
//  Copyright © 2016年  Jierism. All rights reserved.
//

#import "FourLines.h"

static NSString * const kLinesKey = @"kLinesKey";

@implementation FourLines

#pragma mark - Coding
// 回复我们之前归档的对象
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self) {
        self.lines = [aDecoder decodeObjectForKey:kLinesKey];
    }
    return self;
}

// 将所有实例变成编码成aCoder
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:self.lines forKey:kLinesKey];
}

#pragma mark - Copying

- (id)copyWithZone:(NSZone *)zone
{
    // 新建一个新的FourLines对象,并将字符串数组复制进去
    FourLines *copy = [[[self class] allocWithZone:zone] init];
    NSMutableArray *linesCopy = [NSMutableArray array];
    for (  id line in self.lines) {
        [linesCopy addObject:[line copyWithZone:zone]];
    }
    copy.lines = linesCopy;
    return copy;
}

@end

FourLines.m

//
//  ViewController.m
//  Persistence
//
//  Created by  Jierism on 16/7/27.
//  Copyright © 2016年  Jierism. All rights reserved.
//

#import "ViewController.h"
#import "FourLines.h"

static NSString * const kRootKey = @"kRootKey";
@interface ViewController ()

@property(strong,nonatomic)IBOutletCollection(UITextField) NSArray *lineFields;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSString *filePath = [self dataFilePath];
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {

    // 从归档中重组对象,对数据进行解码
        NSData *data = [[NSMutableData alloc] initWithContentsOfFile:filePath];
        NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        FourLines *foueLines = [unarchiver decodeObjectForKey:kRootKey];
        [unarchiver finishDecoding];

        ; i < ; i++) {
            UITextField *theFiled = self.lineFields[i];
            theFiled.text = foueLines.lines[i];
        }

    }

    // 订阅,获取通知
    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationWillResignActive:)
                                                 name:UIApplicationWillResignActiveNotification
                                               object:app];
}

// 接收通知,告诉应用在终止运行或者进入后台之前保存数据
- (void) applicationWillResignActive:(NSNotification *)notification
{
    NSString *filePath = [self dataFilePath];

    // 将对象归档到data实例中
    FourLines *fourLines = [[FourLines alloc] init];
    fourLines.lines = [self.lineFields valueForKey:@"text"];
    NSMutableData *data = [[NSMutableData alloc] init];
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [archiver encodeObject:fourLines forKey:kRootKey];
    [archiver finishEncoding];
    [data writeToFile:filePath atomically:YES];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

// 获取数据文件的完整路径(两步)
- (NSString *)dataFilePath
{
    //1.查找Documents目录
    NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [path objectAtIndex:];
    //2.在后面附加数据文件的文件名
    return [documentsDirectory stringByAppendingPathComponent:@"data.archive"];
}

@end

ViewController.m

三、iOS的嵌入式关系数据库SQLite3

链接到数据库

在项目导航面板中顶部选中项目名称,按下图操作即可

1、创建或打开数据库

2、绑定变量

//
//  ViewController.m
//  SQLite Persistence
//
//  Created by  Jierism on 16/7/27.
//  Copyright © 2016年  Jierism. All rights reserved.
//

#import "ViewController.h"
#import <sqlite3.h>

@interface ViewController ()

@property (strong,nonatomic) IBOutletCollection(UITextField) NSArray *lineFields;

@end

@implementation ViewController

- (NSString *)dataFilePath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:];
    return [documentsDirectory stringByAppendingString:@"data.sqlite"];
}

// 数据库在应用打开时才打开用于加载数据,加载完毕后会关闭
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // 打开数据库,如果在打开时遇到问题则关闭,并抛出断言错误
    sqlite3 *database;
    if (sqlite3_open([[self dataFilePath] UTF8String],&database) != SQLITE_OK) {
        sqlite3_close(database);
        NSAssert(, @"Failed to open database");
    }

    // 建立一个表来保存我们的数据,用IF NOT可以防止数据库覆盖现有数据:如果已有相同名的表则此命令不执行操作
    NSString *createSQL = @"CREATE TABLE IF NOT EXISTS FIELDS "
    "(ROW INTEGER PRIMAY KEY,FIELD_DATA TEXT);";
    char *errorMsg;
    if (sqlite3_exec (database,[createSQL UTF8String],NULL,NULL,&errorMsg) != SQLITE_OK) {
        sqlite3_close(database);
        NSAssert(, @"Error creating table:%s",errorMsg);
    }

    // 数据库中没一行包含一个整型(从0计数)和一个字符串(对应行的内容),加载内容
    NSString *query = @"SELECT ROW,FIELD_DATA FROM FIELDS ORDER BY ROW";
    sqlite3_stmt *statement;
    ,&statement,nil) == SQLITE_OK) {
        // 遍历返回的每一行
        while (sqlite3_step(statement) == SQLITE_ROW) {
            // 抓取行号存储在一个int变量中,抓取字段数据保存在char类型的字符串中
            );
            );
            // 利用从数据库中获取的值设置相应的字段
            NSString *fieldValue = [[NSString alloc] initWithUTF8String:rowData];
            UITextField *field = self.lineFields[row];
            field.text = fieldValue;
        }
        // 关闭数据库连接
        sqlite3_finalize(statement);
    }
    sqlite3_close(database);

    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];

}

- (void)applicationWillResignActive:(NSNotification *)notification
{
    // 打开数据库
    sqlite3 *database;
    if (sqlite3_open([[self dataFilePath] UTF8String], &database) != SQLITE_OK) {
        sqlite3_close(database);
        NSAssert(, @"Failed to open database");
    }

    // 遍历数据库每一行,更新里面的数据
    ; i < ; i++) {
        UITextField *field = self.lineFields[i];
        char *update = "INSERT OR REPLACE INTO FIELDS (ROW,FIELD_DATA)"
                        "VALUES(?,?)";
        char *errorMsg = NULL;

        // 声明一个指向语句的指针,然后为语句添加绑定变量,并将值绑定到两个绑定变量
        sqlite3_stmt *stmt;
        , &stmt, nil) == SQLITE_OK) {
            sqlite3_bind_int(stmt,,i);
            sqlite3_bind_text(stmt,,[field.text UTF8String],-,NULL);
        }
        // 调用sqlite3_step来执行更新,检查并确定其运行正常,然后完成语句,结束循环
        if (sqlite3_step(stmt) != SQLITE_DONE) {
            NSAssert(, @"Error updating table:%s",errorMsg);
        }
        sqlite3_finalize(stmt);
    }
    // 关闭数据库
    sqlite3_close(database);
}

@end

ViewController.m

四、苹果公司提供的持久化工具Core Data

1、键-值编码(KVC)

2、在上下文中结合

3、创建新的托管对象

4、获取托管对象

//
//  AppDelegate.h
//  Core Data Persistance
//
//  Created by  Jierism on 16/7/27.
//  Copyright © 2016年  Jierism. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

@end

AppDelegate.h

#pragma mark - Core Data stack

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

- (NSURL *)applicationDocumentsDirectory {
    // The directory the application uses to store the Core Data store file. This code uses a directory named "jie.Core_Data_Persistance" in the application's documents directory.
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

- (NSManagedObjectModel *)managedObjectModel {
    // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Core_Data_Persistance" withExtension:@"momd"];
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    return _managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
    // The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it.
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    // Create the coordinator and store

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Core_Data_Persistance.sqlite"];
    NSError *error = nil;
    NSString *failureReason = @"There was an error creating or loading the application's saved data.";
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        // Report any error we got.
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
        dict[NSLocalizedFailureReasonErrorKey] = failureReason;
        dict[NSUnderlyingErrorKey] = error;
        error = [NSError errorWithDomain: userInfo:dict];
        // Replace this with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}

- (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] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    return _managedObjectContext;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil) {
        NSError *error = nil;
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
    }
}

@end

AppDelegate.m

//
//  ViewController.m
//  Core Data Persistance
//
//  Created by  Jierism on 16/7/27.
//  Copyright © 2016年  Jierism. All rights reserved.
//

#import "ViewController.h"
#import "AppDelegate.h"

static NSString * const kLineEntityName = @"Line";
static NSString * const kLineNumberKey = @"lineNumber";
static NSString * const kLineTextKey = @"lineText";

@interface ViewController ()

@property (strong,nonatomic) IBOutletCollection(UITextField) NSArray *lineFields;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // 获取对应用委托的引用,使用这个引用获得为我们创建的托管对象上下文
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    NSManagedObjectContext *context = [appDelegate managedObjectContext];

    // 创建一个获取请求并将实体描述传递给它,以便请求指导要检索的对象类型
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:kLineEntityName];

    // 检索存储中所有Line对象,上下文返回库中每一个Line对象。确保返回的是有效数组,否则记录相应日志
    NSError *error;
    NSArray *objects = [context executeFetchRequest:request error:&error];
    if (objects == nil) {
        NSLog(@"There was an error!"); // 进行适当错误处理
    }

    // 使用快熟枚举遍历已获取托管对象的数组,从中提取每个托管对象的lineNum和lineText的值,并用该信息更新用户界面上的文本框
    for (NSManagedObject *oneObject in objects) {
        int lineNum = [[oneObject valueForKey:kLineNumberKey] intValue];
        NSString *lineText = [oneObject valueForKey:kLineTextKey];

        UITextField *theField = self.lineFields[lineNum];
        theField.text = lineText;
    }

    // 在应用终止时获取通知,保存更改
    UIApplication *app = [UIApplication sharedApplication];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:app];
}

- (void)applicationWillResignActive:(NSNotification *)notification
{

    // 与上面一样,获取对应用委托的引用,使用引用获取指向应用的默认托管对象上下文的指针
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    NSManagedObjectContext *context = [appDelegate managedObjectContext];

    NSError *error;

    // 获得每一个字段对应的索引
    ; i < ; i++) {
        UITextField *theField = self.lineFields[i];

        // 为Line实体创建获取请求,创建一个谓词确认存储中是否已经有一个与这个字段对应的托管对象
        NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:kLineEntityName];
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"(%K = %d)",kLineNumberKey,i]; // 谓词
        [request setPredicate:pred];

        // 在上下文中执行后去请求,并检查objects是否为nil

        NSArray *objects = [context executeFetchRequest:request error:&error];
        if (objects == nil) {
            NSLog(@"There was an error!");
        }

        // 声明一个指向NSManagedObject的指针并设置为nil。因为我们不知道要从持久存储中加载托管对象,还是创建新的托管对象。
        // 因此,可以检查与条件匹配的返回对象。如果返回有效的对象就进行加载,否则就创建一个新的托管对象来保存这个字段的文本
        NSManagedObject *theLine = nil;
        ) {
            theLine = [objects objectAtIndex:];
        }else{
            theLine = [NSEntityDescription insertNewObjectForEntityForName:kLineEntityName inManagedObjectContext:context];
        }

        // 使用键-值编码(KVC)来设置行号以及此托管对象的文本
        [theLine setValue:[NSNumber numberWithInt:i] forKey:kLineNumberKey];
        [theLine setValue:theField.text forKey:kLineTextKey];
    }
    // 完成循环,保存更改
    [appDelegate saveContext];
}

@end

ViewController.m

iOS开发-数据持久化的更多相关文章

  1. IOS开发--数据持久化篇之文件存储(一)

    前言:个人觉得开发人员最大的悲哀莫过于懂得使用却不明白其中的原理.在代码之前我觉得还是有必要简单阐述下相关的一些知识点. 因为文章或深或浅总有适合的人群.若有朋友发现了其中不正确的观点还望多多指出,不 ...

  2. IOS开发--数据持久化篇文件存储(二)

    前言:个人觉得开发人员最大的悲哀莫过于懂得使用却不明白其中的原理.在代码之前我觉得还是有必要简单阐述下相关的一些知识点. 因为文章或深或浅总有适合的人群.若有朋友发现了其中不正确的观点还望多多指出,不 ...

  3. iOS开发——数据持久化Swift篇&amp;使用Core Data进行数据持久化存储

    使用Core Data进行数据持久化存储   一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成 ...

  4. iOS开发——数据持久化Swift篇&amp;(一)NSUserDefault

    NSUserDefault //******************** 5.1 NSUserDefault和对象归档 func useNSUserDefault() { //通过单利来创建一个NSU ...

  5. iOS开发——数据持久化Swift篇&amp;文件目录路径获取(Home目录,文档目录,缓存目录等)

    文件目录路径获取(Home目录,文档目录,缓存目录等)   iOS应用程序只能在自己的目录下进行文件的操作,不可以访问其他的存储空间,此区域被称为沙盒.下面介绍常用的程序文件夹目录:   1,Home ...

  6. iOS开发——数据持久化Swift篇&amp;iCloud云存储

    iCloud云存储 import UIKit class ViewController: UIViewController { override func viewDidLoad() { super. ...

  7. iOS开发——数据持久化OC篇&amp;plist文件增删改查操作

    Plist文件增删查改   主要操作: 1.//获得plist路径    -(NSString*)getPlistPath: 2.//判断沙盒中名为plistname的文件是否存在    -(BOOL ...

  8. iOS开发——数据持久化Swift篇&amp;(四)CoreData

    CoreData import CoreData class ViewController: UIViewController { override func viewDidLoad() { supe ...

  9. iOS开发——数据持久化Swift篇&amp;(三)SQLite3

    SQLite3 使用 //******************** 5.3 SQLite3存储和读取数据 func use_SQLite3() { //声明一个Documents下的路径 var db ...

随机推荐

  1. 魅族mx4 pro连电脑,adb无法获取devices信息解决

    根据 flyme 的文档: K:\MX4 USB Reference Manual\简体\MX4_ADB_参考说明书.txt 操作如下: 二.Windows XP中文环境1.  建立或修改C:\Doc ...

  2. Linux的用户及用户组

    一./etc/group下存储当前系统中所有的用户组信息 -Group:   x   : 123  :abc,def,xyz -组名称:组密码占位符:组编号:组中用户名列表 二./etc/gshado ...

  3. Sublime Text 2 增加python版本

    当系统中装有多个python版本时,Sublime Text 2  使用哪个版本需要手动添加 键入一下内容,path输入python的安转路径 保存至Python27.sublime-build文件 ...

  4. Keras学习~试用卷积~跑CIFAR-10

    import numpy as np import cPickle import keras as ks from keras.layers import Dense, Activation, Fla ...

  5. git -- 如何解决冲突

    遇到冲突,首先要编辑冲突文件,可以使用vim或者其他工具,冲突文件变现为: <<<<HEAD 到 ==== :代表本地分支的修改内容 ==== 到 >>>&g ...

  6. 服务器端json数据文件分割合并解决方案

    问题引入 Json 是什么就不多说了,本文把Json理解成一种协议. 印象之中,Json貌似是前端的专属,其实不然,服务器端组织数据,依然可以用Json协议. 比如说,某公司有一套测评题目(基于Jso ...

  7. 通过源码理解UST(用户栈回溯)

    UST原理:如果gflags标志中包含了UST标志,堆管理器会为当前进程分配一块内存,这个内存区域就是UST数据库(user-mode stack trace database),并建立一个STACK ...

  8. http响应状态码301和302

    HTTP返回码中301与302的区别 (2012-10-15 22:06:09) 一.官方说法 301,302 都是HTTP状态的编码,都代表着某个URL发生了转移,不同之处在于: 301 redir ...

  9. UICollection 重排 和汉字拼音

    http://nshint.io/blog/2015/07/16/uicollectionviews-now-have-easy-reordering/ NSMutableString *str = ...

  10. struts2中错误处理

    定义一个 package,然后其他package都继承 这个package struts-global 就 有了这个错误处理功能了 然后再自己写个类 struts.xml <constant n ...