IOS数据存储的几种方式

        XML属性列表(plist)

        归档 Preference(偏好设置) 

        NSKeyedArchiver归档(NSCoding)

        SQLite3

        Core Data

先来研究一下前三种。

        每个iOS应用都有自己的应用沙盒(应用沙盒就是文件系统目录),与其他文件系统隔离。应用必须待在自己的沙盒里,其他应用不能访问该沙盒。沙盒的结构如下所示:

       应用程序包:(上图中的QQ.app)包含了所有的资源文件和可执行文件。
       Documents:保存应用运行时生成的需要持久化的数据,iTunes同步设备时会备份该目录。例如,游戏应用可将游戏存档保存在该目录。
       tmp:保存应用运行时所需的临时数据,使用完毕后再将相应的文件从该目录删除。应用没有运行时,系统也可能会清除该目录下的文件。iTunes同步设备时不会备份该目录。
       Library/Caches:保存应用运行时生成的需要持久化的数据,iTunes同步设备时不会备份该目录。一般存储体积大、不需要备份的非重要数据。
       Library/Preference:保存应用的所有偏好设置,iOS的Settings(设置)应用会在该目录中查找应用的设置信息。iTunes同步设备时会备份该目录。

每个目录的获取方法

           // 临时目录

            NSString *path = NSTemporaryDirectory();

            // /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/A8519BA5-FB34-4B31-BB72-3948264AFB37/tmp/

            // 主目录

            NSString *path = NSHomeDirectory();

            //  /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/E6A8A443-55CA-463B-886C-DAAF69E8F3BC

            

            // Documents 目录,第三个参数为yes显示全路径,为NO时显示位波浪线 “~”

];

            // /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/61B033AA-BBFB-4A3A-AD6E-2E332B78C2ED/Documents

            ];

            //  ~/Documents

            // cache 目录

];

            // /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/1B4923AF-4B1F-4C7A-941E-D3621D7945C3/Library/Caches

            // PreferencePanes 目录

            ];

            // /Users/song/Library/Developer/CoreSimulator/Devices/B040D34E-CF0E-41C2-9BD0-C309566CC349/data/Containers/Data/Application/D654173E-DC23-4951-8C28-016878B5246B/Library/PreferencePanes

还有一个特殊的单例对象用来保存用户设置

            // 默认保存到PreferencePanes目录

            [[NSUserDefaults standardUserDefaults] setObject:@“hah” forKey:@"1"];

            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@“2”];

1、plist文件

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

        如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,就可以使用writeToFile:atomically:方法直接将对象写到属性列表文件中.

        保存数据

            // plist保存数据

            // 保存用户名、密码、记住密码、自动登录

            NSMutableDictionary *dict = [NSMutableDictionarydictionary];

            [dict setObject:_userField.text forKey:@"user"];

            [dict setObject:_pwdField.text forKey:@"pwd"];

            [dict setObject:@(_rmbPwdSwitch.on) forKey:@"rmb"];

            [dict setObject:@(_autoLoginSwitch.on) forKey:@"auto"];

            // 获取cache路径

];

            // 取得文件的全路径

            NSString *filePath = [cachePath stringByAppendingPathComponent:@"userInfo.plist"];

            // 写入到文件

            [dict writeToFile:filePath atomically:YES];

 

       读取数据

    // 读取plist中数据,显示在textField中

    // 获取cache路径

];

    // 取得文件的全路径

    NSString *filePath = [cachePath stringByAppendingPathComponent:@"userInfo.plist"];

    // 读取字典数据

    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];

    // 给控件赋值

    NSString *userName = dict[@"user"];

    NSString *pwd  = dict[@"pwd"];

    BOOL rmb =  dict[@"rmb"];

    BOOL autoLogin = dict[@"autoLogin"];

    

    _userField.text = userName;

    

    if (rmb == YES)

    {

        _pwdField.text = pwd;

    }

 

    _rmbPwdSwitch.on = rmb;

    _autoLoginSwitch.on = autoLogin;

这里目前还有问题,那就是读取出来的bool变量全是YES。等明天研究一下再。

 问题出来了,读取字典中得bool变量时要转换一下

    // 给控件赋值

    NSString *userName = dict[@"user"];

    NSString *pwd  = dict[@"pwd"];

    BOOL rmbPwd =  [dict[@"rmb"] boolValue]; // 要转换一下,不然读取结果不准确

    BOOL login = [dict[@"autoLogin"] boolValue];

2、Preference 偏好设置

内部实现也是一个plist文件。不过是否系统控制路径和名称。只需写入和读取就行,不用关系细节。

写入数据

            // preference 偏好设置

             NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults]; // 单例对象

            [userDefault setObject:_userField.text forKey:@"user"];

            [userDefault setObject:_pwdField.text forKey:@"pwd"];

            [userDefault setBool:_rmbPwdSwitch.on forKey:@"rmb"];

            [userDefault setBool:_autoLoginSwitch.on forKey:@"autoLogin"];

 读取数据

    // 偏好设置,读取数据,

    NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];

    NSString *name = [userDefault stringForKey:@"user"];

    NSString *pwd = [userDefault stringForKey:@"pwd"];

    BOOL rmbPwd = [[userDefault boolForKey:@“rmb”] boolValue];

    BOOL login = [[userDefault boolForKey:@“autoLogin”] boolValue];

    // 给控件赋值

    _userField.text = name;

    if (rmbPwd == YES)

    {

        _pwdField.text = pwd; // 记住密码才赋值

    }

    _rmbPwdSwitch.on = rmbPwd;

    _autoLoginSwitch.on = login;

    if (login) { // 自动登录

        

        [self login:nil];

    }

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

 3、NSKeyedArchiver 归档

如果对象是NSString、NSDictionary、NSArray、NSData、NSNumber等类型,可以直接用NSKeyedArchiver进行归档和恢复
不是所有的对象都可以直接用这种方法进行归档,只有遵守了NSCoding协议的对象才可以
NSCoding协议有2个方法:
        encodeWithCoder:
每次归档对象时,都会调用这个方法。一般在这个方法里面指定如何归档对象中的每个实例变量,可以使用encodeObject:forKey:方法归档实例变量
        initWithCoder:
每次从文件中恢复(解码)对象时,都会调用这个方法。一般在这个方法里面指定如何解码文件中的数据为对象的实例变量,可以使用decodeObject:forKey方法解码实例变量。

    1、常见类型

写入常用类型

            // 归档对象NSKeyedArchiver

            // 获取路径

];

            // 取得文件的全路径

            NSString *filePath = [cachePath stringByAppendingPathComponent:@"info.data"];

            

//            [NSKeyedArchiver archiveRootObject:_userField.text toFile:filePath];

            NSArray *all = @[_userField.text,_pwdField.text,@(_rmbPwdSwitch.on),@(_autoLoginSwitch.on)];

            [NSKeyedArchiver archiveRootObject:all toFile:filePath];

读取

    // 获取路径

];

    // 取得文件的全路径

    NSString *filePath = [cachePath stringByAppendingPathComponent:@"info.data"];

    // 归档对象NSKeyedArchiver

//    NSString *name =  [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

    NSArray *all = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];

    NSLog(@"%@",all);

    2、自定义对象

 要读写自定义对象,自定义对象要遵守NSCoding协议,并实现两个方法,一个打包initWithCoder:,一个解包encodeWithCoder:

 以联系人为例

    #import <Foundation/Foundation.h>

 

    @interface SLQContact : NSObject <NSCoding>

 

    /*姓名*/

    @property (strong, nonatomic) NSString *name;

    // 手机号

    @property (strong, nonatomic) NSString *phone;

 

    + (instancetype)contactWithName:(NSString *)name andPhone:(NSString *)phone;

    @end

实现协议方法 

    #import "SLQContact.h"

 

    @implementation SLQContact

 

    + (instancetype)contactWithName:(NSString *)name andPhone:(NSString *)phone

    {

        SLQContact *contact = [[self alloc] init];

        contact.name = name;

        contact.phone = phone;

        return  contact;

    }

    // 解包,按照key找属性

    - (void)encodeWithCoder:(NSCoder *)aCoder

    {

        [aCoder encodeObject:self.name forKey:@"name"];

        [aCoder encodeObject:self.phone forKey:@"phone"];

    }

    // 打包,就是给属性指定一个key

    - (id)initWithCoder:(NSCoder *)aDecoder

    {

        if (self = [super init])

        {

            self.name = [aDecoder decodeObjectForKey:@"name"];

            self.phone = [aDecoder decodeObjectForKey:@"phone"];

        }

        return  self;

    }

    @end 

然后在联系人控制器中读写归档文件

定义一个宏用来获取文件路径

// 获得归档文件的路径

#define SLQFilePath [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[] stringByAppendingPathComponent:@"info.data"]

写如归档文件

    // 添加按钮,按下后进入添加联系人界面

    - (IBAction)addBtn:(id)sender {

        //

    //    [self performSegueWithIdentifier:@"contactToAdd" sender:nil];

        // 通过代码获取storyboard中得控制器

        UIStoryboard *story = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

        // 获取main。storyboard中得控制器,以标识符区分

        SLQAddViewController* addVC = [story instantiateViewControllerWithIdentifier:@"add"];

        // block封装待执行的代码

        addVC.block= ^(SLQContact *contact){

            // 更新模型

            [self.contacts addObject:contact];

            // 刷新表格

            [self.tableView reloadData];

            // 3.保存联系人,注意:如果归档数组,底层会遍历数组元素一个一个归档

            [NSKeyedArchiverarchiveRootObject:self.contactstoFile:SLQFilePath];

        };

        // 跳转到添加联系人界面

        [self.navigationController pushViewController:addVC animated:YES];

    } 

 读取归档文件,在属性contacts的setter方法中进行读取。

    // 重写set方法

    - (NSMutableArray *)contacts

    {

        if (_contacts == nil)

        {

            // 读取归档文件

            _contacts = [NSKeyedUnarchiver unarchiveObjectWithFile:SLQFilePath];

            if (_contacts == nil) { // 如果读取的文件为空,初始化数组

                  _contacts = [NSMutableArray array];

            }

        }

        return _contacts;

    }

 

还有两种存储方式,属于数据库范畴,继续学习。

 

 

IOS笔记048-数据存储的更多相关文章

  1. 李洪强iOS开发之数据存储

    李洪强iOS开发之数据存储 iOS应用数据存储的常用方式 1.lXML属性列表(plist)归档 2.lPreference(偏好设置) 3.lNSKeyedArchiver归档(NSCoding) ...

  2. ios中常见数据存储方式以及SQLite常用的语句

    在iOS中,根据不同的需求对应的有多种数据存储方式: 1.NSUserdefaults  将数据存储到沙盒中(library),方便易用,但是只能存储系统提供的数据类型(plist),不能存储自定义的 ...

  3. ios开发之数据存储

    iOS应用数据存储的常用方式 XML属性列表(plist)归档 Preference(偏好设置) NSKeyedArchiver归档(NSCoding) SQLite3 Core Data 应用沙盒 ...

  4. iOS中的数据存储

    SQLite3 SQLite3是一款开源的嵌入式关系型数据库,可移植性好,易使用,内存开销小. SQLite3是无类型的,意味着你可以保存任何类型的数据到任意表的任意字段中. SQLite3常用的4种 ...

  5. Android 学习笔记之数据存储SharePreferenced+File

    学习内容: Android的数据存储.... 1.使用SharedPreferences来保存和读取数据... 2.使用File中的I/O来完成对数据的存储和读取...   一个应用程序,经常需要与用 ...

  6. iOS - OC NSUserDefaults 数据存储

    前言 @interface NSUserDefaults : NSObject 用来保存应用程序设置和属性.用户保存的数据.用户再次打开程序或开机后这些数据仍然存在.如果往 userDefaults ...

  7. iOS - Swift NSUserDefaults 数据存储

    前言 public class NSUserDefaults : NSObject 用来保存应用程序设置和属性.用户保存的数据.用户再次打开程序或开机后这些数据仍然存在.如果往 userDefault ...

  8. MySQL学习笔记之数据存储类型

    说明:本文是作者对MySQL数据库数据存储类型的小小总结. Numeric Type (数字类型) 1.TINYINT.SMALLINT.MEDIUMINT.INT.BIGINT主要根据存储字节长度不 ...

  9. Android开发笔记之: 数据存储方式详解

    无论是神马平台,神马开发环境,神马软件程序,数据都是核心.对于开发平台来讲,如果对数据的存储有良好的支持,那么对应用程序的开发将会有很大的促进作用.总体的来讲,数据存储方式有三种:一个是文件,一个是数 ...

随机推荐

  1. intelij idea相关笔记--持续更新

    一.快捷键: Ctrl+F 文件内查找 Ctrl+Shift+F 全局查找 Ctrl+Shift+N 查找文件 Ctrl+Alt+← 返回上一步 Ctrl+Alt+→ 返回下一步 二.编译相关: 如果 ...

  2. Visual Studio 2015 终于还是装上了

    win8.1系统 vs2015.preview_ult_CHT.iso 大小4.46G, http://download.microsoft.com/download/9/9/1/99133C05-3 ...

  3. PHP:php遍历数组each()方法总结

    each()的作用是将数组当前元素的键值对拆成一个新数组,并把下一个元素作为当前元素.比如Array(...,'Robert'=>'Bob',...)中的'Robert'=>'Bob'键值 ...

  4. hdu-1179 Ollivanders: Makers of Fine Wands since 382 BC.---二分图匹配模板

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1179 题目大意: 有n个人要去买魔杖,有m根魔杖(和哈利波特去买魔杖的时候一样,是由魔杖选人).接下 ...

  5. Flutter /bin/sh: /packages/flutter_tools/bin/xcode_backend.sh: No such file or directory

    自己写项目中遇到的一个问题, 可以出来是路径找不到,应该是FLUTTER_ROOT这个全局变量没有取到值的原因 1.检查xcode_backend.sh 是否真的存在 2.网上说的:Target -& ...

  6. Quartz 配置文件属性

    主要配置 Property Name Req'd Type Default Value org.quartz.scheduler.instanceName no string 'QuartzSched ...

  7. cout对象一些常用方法的总结

    cout.precision(n); 这个方法的功能是,设置精度为n,返还值是上一次的设置精度. #include <iostream> using namespace std; int ...

  8. Drupal常用的模块

    CCK (Content Construction Kit ) : 添加字段模块 Views:生成列表 Tinymce:(Wysiwyg Editor) 常用的编辑器之一 Ajax Form Buil ...

  9. css3媒体查询中device-width和width的区别

    1.device-width 定义:定义输出设备的屏幕可见宽度. 不管你的网页是在safari打开还是嵌在某个webview中,device-width都只跟你的设备有关,如果是同一个设备,那么他的值 ...

  10. 【Java】基本数据类型以及其转换

    整理了一下Java基本数据类型和面试可能涉及的知识.      字节数(byte)  位数(bit)  取值范围 整型  byte  1  8  -2^7 ~ 2^7 -1 short   2  16 ...