美文网首页demo开发技巧iOS
数据存储方式、沙盒路径、FMDB

数据存储方式、沙盒路径、FMDB

作者: CoderZb | 来源:发表于2016-07-30 13:11 被阅读475次

    沙箱模型的有四个文件夹


    documents,tmp,app,Library。
    

    四个文件夹分别是什么


    Documents 目录:您应该将所有de应用程序数据文件写入到这个目录下。这个目录用于存储用户数据或其它应该定期备份的信息。
    
    tmp 目录:这个目录用于存放临时文件,保存应用程序再次启动过程中不需要的信息。
    
    AppName.app 目录:这是应用程序的程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以您在运行时不能对这个目录中的内容进行修改,否则可能会使应用程序无法启动。
    
    Library 目录:这个目录下有两个子目录:Caches 和 Preferences
    
    Library/Preferences 目录:包含应用程序的偏好设置文件。您不应该直接创建偏好设置文件,而是应该使用NSUserDefaults类来取得和设置应用程序的偏好.(利用NSUserDefaults存储的数据就是在沙盒中的这个文件夹中)
    
    Library/Caches 目录:用于存放应用程序专用的支持文件,保存应用程序再次启动过程中需要的信息。
    

    沙盒中各个目录的路径获取方式


    1.获取沙盒中home目录(主目录,沙盒的最外层)的路径
        NSString *homeDir = NSHomeDirectory();
    
        NSLog(@"获取沙盒中home目录路径\n %@",homeDir);
    
    打印结果
      2016-06-17 21:12:06.264 sd[9698:422028] 获取沙盒中home目录路径
    
     /Users/zhangbin/Library/Developer/CoreSimulator/Devices/46A6D7C4-D373-4684-A640-4B4A1FF2BC6E/data/Containers/Data/Application/5E081742-A012-48E6-B70A-77906491B714
    

    2.获取沙盒中Documents目录的路径
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    
        NSString *docDir = [paths objectAtIndex:0];
    
        NSLog(@"获取沙盒中Documents目录的路径\n %@",docDir);
    
    打印结果:
        2016-06-17 21:12:06.264 sd[9698:422028] 获取沙盒中Documents目录的路径
    
         /Users/zhangbin/Library/Developer/CoreSimulator/Devices/46A6D7C4-D373-4684-A640-4B4A1FF2BC6E/data/Containers/Data/Application/5E081742-A012-48E6-B70A-77906491B714/Documents
    

    3.获取沙盒中Caches目录的路径

        NSArray *path2 = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    
        NSString *cachesDir = [path2 objectAtIndex:0];
    
        NSLog(@"获取沙盒中Caches目录的路径\n %@",cachesDir);
    
    打印结果:
        2016-06-17 21:12:06.264 sd[9698:422028] 获取沙盒中Caches目录的路径
       /Users/zhangbin/Library/Developer/CoreSimulator/Devices/46A6D7C4-D373-4684-A640-4B4A1FF2BC6E/data/Containers/Data/Application/5E081742-A012-48E6-B70A-77906491B714/Library/Caches
    

    4.获取沙盒中tmp目录的路

         NSString *tmpDir = NSTemporaryDirectory();
         NSLog(@"获取沙盒中tmp目录的路径\n %@",tmpDir);
    

    打印结果:

    2016-06-17 21:12:06.265 sd[9698:422028] 获取沙盒中tmp目录的路径
    
     /Users/zhangbin/Library/Developer/CoreSimulator/Devices/46A6D7C4-D373-4684-A640-4B4A1FF2BC6E/data/Containers/Data/Application/5E081742-A012-48E6-B70A-77906491B714/tmp/
    
    

    NSUserDefaults详细介绍


    • 1.NSUserDefaults类用于保存应用程序设置和属性以及用户数据。例如,你可以存储用户在应用程序中使用的图片或默认颜色方案,或者背景等。这些对象存储在iOS所谓的“defaults系统”中。
    • 2.iOS的defaults系统在整个app中都是可用的,因此存放到defaults系统中的数据也是整个应用程序生命周期中可用的。也就是说,无论用户关闭程序还是关机,在用户再次打开程序或开机后这些数据仍然存在。
    • 3.从NSUserDefaults返回的值是不可改变的,即便是你在存储的时候使用的是可变的值。例如你使用mutable string做为“MyStringDefault”的值,当你做使用stringForKey:方法获取的值,这个值仍然是不可变的。
    • 4.NSUserDefaults是单例,同时也是线程安全的
    • 5.NSUserDefaults可以存储的数据类型只能是property list类型的数据。(NSData,NSString,NSNumber,NSDate,NSArray,NSDictionary)
      如果你想保存其他类型,如UIImage,你应该进行编码(即archive),或者将它转换为NSData、NSNumber或者NSString。

    • 6.[NSUserDefaults standardUserDefaults]用来记录一下永久保留的数据非常方便,不需要读写文件,而是保留到一个NSDictionary字典里,由系统保存到文件里,系统会保存到该应用下的/Library/Preferences/gongcheng.plist文件中。需要注意的是如果程序意外退出,NSUserDefaultsstandardUserDefaults数据不会被系统写入到该文件,不过可以使用[[NSUserDefaultsstandardUserDefaults] synchronize]命令直接同步到文件里,来避免数据的丢失。

    • 手动保存的文件在documents文件里,Nsuserdefaults保存的文件在Library/Preferences 目录文件夹里;


    NSUserDefaults六大方法:


    一.得到共享的NSUserDefaults实例

    + (NSUserDefaults *)standardUserDefaults    
    

    二.初始化一个NSUserDefaults对象

    - (id)initWithUser:(NSString *)username
    

    三.得到默默认值

    - objectForKey:;
    
    - stringForKey:;
    
    - arrayForKey:;
    
    - dictionaryForKey:;
    
    - dataForKey:;
    
    - stringArrayForKey:;
    
    - integerForKey:;
    
    - floatForKey:;
    - doubleForKey:;
    
    - boolForKey:;
    
    - URLForKey:;
    

    四.设置默认值

    - setInteger:forKey:;
    
    - setFloat:forKey:;
    
    - setDouble:forKey:;
    
    - setBool:forKey:;
    
    - setURL:forKey:;
    

    五.记录默认值

    - registerDefaults:;
    

    六.删除默认值

    - removeObjectForKey:;
    

    如何使用NSUserDefaults?


    你可以把它当做是一个小型的数据库,在存储和读取数据之前,你需要调用方法: standardUserDefaults :
    如:

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    

    我把这个方法理解为,打开数据库的大门,这样你就可以对里面的数据做各种操作,也可以将存储数据进来。
    存储数据和读取数据有各种方法,需要注意的是,存储数据需要完成方法 synchronize:,这个方法完成的作用是同步数据,也就是将你做出改变的数据更新。
    如:

    [defaults synchronize];
    

    NSUserDefaults具体用法


    • IOS提供了一个轻量级的快速数据存储方式:NSUserDefaults,对于SQLite这样的数据库方式,适合大量数据的存储。

    • 程序运行的时候从用户默认的数据库中读取程序的设置,同时NSUserDefaults的缓存避免了在每次读取数据时候都打开用户默认数据库的操作,所有数据都放在内存中,读写速度很快。


    1.获取 NSUserDefaults

    这是一个单例,获取非常方便,随时可以调用:

    [NSUserDefaults standardUserDefaults];
    

    2.写入数据到NSUserDefaults中

    [[NSUserDefaults standardUserDefaults] setInteger:10 forKey:@"test"];
    
    [[NSUserDefaults standardUserDefaults] setFloat:10.0 forKey:@"test"];
    
    ..... NSUserDefaults 支持多种数据类型,用 key来标示
    

    3.读取NSUserDefaults中存储的数据

     int a = [[NSUserDefaults standardUserDefaults] integerForKey:@"test"];
    
     float a = [[NSUserDefaults standardUserDefaults] floatForKey:@"test"];
    
     。。。当然也支持其他各种类型
    

    4.保存数据,实现持久化存储

    [[NSUserDefaults standardUserDefaults] synchronize];
    

    5.判断数据是否存在

     if([[NSUserDefaults standardUserDefaults] objectForKey:@""test"]==nil){
      ......
    }else{
      ......
    }
    

    NSUserDefaults和Property List(属性表,也就是plist文件)区别


    • Property List (属性表)
      • 定义:Property List文件是一种用来存储序列化后的对象 的文件。属性列表文件的文件扩展名 为.plist,因此通常被称为 plist 文件。
      • pl是一种格式,包含了(NSData,NSString,NSNumber,NSDate,NSArray,NSDictionary 这六种任意组合创建的结构体)

    • NSUserDafults
      • NSUserDafults相当于一个缓存,而plist是一个文件。
      • NSUserDefault,它其实也是以property list 的形式来存储的,但是它有限制,比如说NSColor和NSFont等类型式不能够直接存储的,我们必须要转换他们,要把他们转换成NSData类型来存。

    如何获取利用NSUserDefaults存储数据的路径?

    • 1.先获取沙盒中home目录(主目录,沙盒的最外层)的路径
      NSString *homeDir = NSHomeDirectory();
      NSLog(@"获取沙盒中home目录路径\n %@",homeDir);
    • 2.然后找到Library/Preferences这个目录,这个目录下的plist文件就是数据的最终路径

    iOS中数据存储方式

    • 方式1.Plist(利用writeToFile/arrayWithContentsOfFile)
    // 向plist文件中存数据
     NSArray *data = @[@"Marry",@"Lucy"];
     [data writeToFile:@"/Users/zhangbin/Desktop/zhangbin.plist" atomically:YES];
    
    // 再次向这个plist文件中存数据时,首先必须得取出这个plist中的数据,然后再添加数据,最后才可以写入到plist文件
     NSMutableArray *data = [NSMutableArray arrayWithContentsOfFile:@"/Users/zhangbin/Desktop/zhangbin.plist"];
    [data addObject:@"Tom"];
    [data writeToFile:@"/Users/zhangbin/Desktop/zhangbin.plist" atomically:YES];
    
    

    精华demo

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @property(nonatomic,strong)NSDictionary *Dic;
    @property(nonatomic,strong)NSMutableDictionary *sectionDic;
    @end
    
    @implementation ViewController
    
    -(NSDictionary *)Dic{
        if(_Dic == nil){
            _Dic = [NSDictionary dictionary];
        }
        return _Dic;
    }
    -(NSMutableDictionary *)sectionDic{
        if(_sectionDic == nil){
            _sectionDic = [NSMutableDictionary dictionary];
        }
        return _sectionDic;
    }
    
    // 例2:复杂测试
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSMutableArray * sectionArr = [[NSMutableArray alloc] init];
        NSMutableDictionary * rowDic = [[NSMutableDictionary alloc] init];
        
        for (int i = 0; i < 2; i ++) {
            
            for (int j = 0; j < 4; j ++) {
                
                [rowDic setObject:@"NO" forKey:@"selected"];// 等价rowDic[@"selected"]=@"NO";
                [sectionArr addObject:rowDic];
            }
            // 总结:key不能为NSNumber,key只能为字符串。 value可以为字符串,也可以为NSNumber
            // [self.sectionDic setObject:sectionArr forKey:@(i)];// 错误写法
            
            // 正确写法
            [self.sectionDic setObject:sectionArr forKey:[NSString stringWithFormat:@"%zd",i]];// 等价 self.sectionDic[ [NSString stringWithFormat:@"%zd",i]] = sectionArr;
        }
        
        /*****************************写plist文件到本地路径*****************************/
        BOOL a = [self.sectionDic writeToFile:@"/Users/zhangbin/Desktop/Company/zb6.plist" atomically:YES];
        if (a == 1) {
            NSLog(@"写入成功");
        }else{
            NSLog(@"写入失败");
        }
        NSLog(@"%@",self.sectionDic);
        
        /*****************************写plist文件到沙盒********************************/
        // 获取沙盒中Documents目录的路径
        NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
        NSString *plistPath1 = [paths objectAtIndex:0];
        //拼接plist文件,得到完整的文件名
        NSString *filename = [plistPath1 stringByAppendingPathComponent:@"CoderZb.plist"];
        // 打印plist文件的总路径
        NSLog(@"%@",filename);
        [self.sectionDic writeToFile:filename atomically:YES];
        // 打印读取plist文件
        NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filename];
        // 打印plist文件中的内容
        NSLog(@"%@",dict);
    
    }
    
    // 例1:简单测试
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        
        // 总结:key不能为NSNumber,key只能为字符串。 value可以为字符串,也可以为NSNumber
        //    NSDictionary *dict3=@{@"a":@"b",@"c":@"d"};// 写入成功
        //    NSDictionary *dict3=@{@(1):@"b",@"c":@"d"};// 写入失败
        NSDictionary *dict3=@{@"a":@(2),@"c":@"d"};// 写入成功
        [dict3 writeToFile:@"/Users/zhangbin/Desktop/Company/zhangbin.plist"  atomically:YES];
    
    }
    
    @end
    
    打印。.png 写入到plist文件.png
    • 方式2.Preference(利用NSUserDefaults取得和设置应用程序的偏好.)
    // 将NSString 对象存储到 NSUserDefaults 中
      NSString *passWord = @"1234567";
     NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
      [user setObject:passWord forKey:@"userPassWord"];
    
    // 从NSUserDefaults中取出数据,只需要取出key 对应的值就好了  
      NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
      NSString *passWord = [ user objectForKey:@"userPassWord"];
    
    
    • 方式3.NSCoding(利用NSKeyedArchiver\NSkeyedUnarchiver)
        /************toFile和unarchiveObjectWithFile的参数为字符串类型的路径*********************/
    
        NSDictionary *glossary = [NSDictionary dictionaryWithObjectsAndKeys:@"A",@"B", @"C",@"D",nil];
      
        NSString *path =  [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"glossary.archive"];
     
      // 归档时,toFiled的参数写成路径。解档时,objectForKey的参数也必须写成路径
    
      // 使用NSKeyedArchiver归档
        [NSKeyedArchiver archiveRootObject:glossary toFile:path];
        NSLog(@"%@",path);
     
      // 使用NSKeyedUnarchiver解档
        NSDictionary *readglossary = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
    
        for(NSString *key in readglossary){
            NSLog(@"%@: %@",key,[readglossary objectForKey:key]);
        }
    
            
    
        /************toFile和unarchiveObjectWithFile的参数仅仅是普通的字符串*********************/
    
        // dictionaryWithObjectsAndKeys的参数特殊,从冒号开始,@"A"为键,@"B"为值,以此类推
     NSDictionary *glossary = [NSDictionary dictionaryWithObjectsAndKeys:@"A",@"B", @"C",@"D",nil];
    
      
      // 归档时,toFiled的参数写成字符串.那么解档时,objectForKey的参数也必须写成字符串
        [NSKeyedArchiver archiveRootObject:glossary toFile:@"glossary.archive"];
    
      // 将文件glossary.archive中的数据读到字典对象并显示出来
        NSDictionary *readglossary = [NSKeyedUnarchiver unarchiveObjectWithFile:@"glossary.archive"];
    
        for(NSString *key in readglossary){
            NSLog(@"%@: %@",key,[readglossary objectForKey:key]);
        }
    
    
    方式3打印结果:
    
    2016-06-17 20:09:12.430 1[7975:345839] B: A
    
    2016-06-17 20:09:12.432 1[7975:345839] D: C
    
    2016-06-17 20:09:12.432 1[7975:345839] E: E
    
    
    
    • 方式4.SQLite3(SQLite的第三个版本)
    SQLite3是数据库技术,纯C语言版本,是轻量级
    
    
    • 方式5.Core Data(苹果原声的数据存储方式)
    Core Data是数据库技术,以SQLite3为基础的OC版本,且是重量级
    
    • 各个方式的优缺点:

    • 1.方式1和方式2只能存简单的数据类型的对象,例如存NSArray,NSDictionary.方式1和方式2都是存储成plist文件,所以这两种方式本质是一样的

    • 2.方式3只要遵守NSCoding协议,并实现方法,就能够将任何类型的对象存入沙盒

    • 3.方式和方式2和方式3都只能存小数据,不能存大数据

    • 4.存大数据必须利用数据库也就是利用方式4或者方式5.因为利用数据库检索数据非常快,如果你想从数据库的1000个数据里面取出100和150之间的数据,不用读取全部的1000个数据,仅仅利用命令即可快速检索到。如果不利用数据库,而是利用方式1,方式2,方式3,必须得先把1000个数据读取出来,然后再截串,速度非常慢。

    • 5.对于大批量的数据,我们要对这些数据做缓存的话,不能用Plist、Preference、NSCoding做缓存,应该用SQLite3或者Core Data来做缓存.如果是做小批量的数据,我们用Plist、Preference、NSCoding当中的哪一个做缓存都行

    • 注意:无论采取了什么方式,其实都是把数据存储到文件中了,只是这个文件的类型决定了能存大数据还是小数据,没有什么可深奥的。因为文件的类型只有用对应的软件开,例如 sqlite后缀的文件只能用navicat打开,navicat是一款数据库管理工具。所以一般我们说将数据存到数据库中(不好理解),换句话说就是将数据存到了sqlite后缀的文件中(好理解)


    数据库


    • 数据库就是存储和管理数据的仓库

    • SQLite是轻量级的嵌入式数据库(非常的轻),一般用于Android、iPhone手机上,在设备中,SQLite只占用几百K的内存,处理速度比Mysql数据库块

    • 数据库分为关系型数据库(主流)、对象型数据库

    • 常用的关系型数据库:

      • 1.PC端:Oracle、Mysql、SQLServer、Access、DB2、Sybase

      • 2.移动客户端:SQLite


    使用sqlite3报错的解决办法


    92-01.png

    归档、解档


    92-05.png 92-06.png

    注意归档\解档 和 对象转成NSData数据\将NSData数据转成对象的区别


    • 归档
     [NSKeyedArchiver archiveRootObject:shops toFile:@"/Users/apple/Desktop/shops.data"];
    
    • 解档
     NSMutableArray *shops = [NSKeyedUnarchiver unarchiveObjectWithFile:@"/user/xxx"];
    
    • 对象shop转成NSData数据
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:shop];
    
    • 将NSData数据转成对象shop
    ZBShop *shop = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    

    用SDWebImage清除图片缓存功能


    • 清除原理就是:因为用户浏览的缓存图片默认会存到沙盒中的Library中的Caches目录下,所以SDWebImage框架底层会找到沙盒的Library中的Caches目录下的图片缓存,删除缓存在这里面的图片。没啥难的,就是找到缓存文件,删除即可
    • 验证:
      • 步骤1:在程序中输入如下代码
        NSArray *path2 =                     NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
        NSString *cachesDir = [path2 objectAtIndex:0];
        NSLog(@"获取沙盒中Caches目录的路径\n %@",cachesDir);
    
    • 步骤2:浏览程序中的图片

    • 步骤3:复制步骤1中打印出来的路径,查找路径的位置

    • 步骤4:点击清除按钮,执行SDWebImage清除缓存的代码,看里面的文件是否消失,如果消失了,可以验证确实清除了缓存的图片。

    • 步骤5:如果还不放心,可以在缓存路径的目录下,手动粘贴几张图片,几个文件夹等等,然后你再点击清除按钮,发现也能删除这些手动粘贴的数据

    • 步骤6:附动态截图

    59-41.gif

    封装一个分类:根据文件夹路径,计算文件夹的大小


    • 利用NSFileManager,可以获取文件夹,从而操纵这个文件夹,你可以删除这个文件夹中的内容

    • 系统底层不能够计算文件夹的大小,只能计算文件的大小,因为文件夹没有大小属性,文件才有大小属性,所以如果我们想要得到文件夹的大小,如何做呢?

      • 答: 利用NSFileManager遍历出这个文件夹中的文件,将遍历出的每个文件的大小相加,从而间接的得到文件夹的大小
    • 想要永久的将图片数据放入缓存中,必须放在沙盒的Library的Caches文件中,不要放在temp(临时的文件夹,系统随机删除),也不要放在Documents中,放在Documents中时候,你请求苹果审核你的app时,会被拒的,原因就是不能再Documents中放下载的缓存图片


    利用SDWebImage清除图片缓存和利用NSFileManager清除图片缓存


    1.利用SDWebImage清除图片缓存.

    [[SDImageCache sharedImageCache] clearDisk];
    

    2.利用NSFileManager清除图片缓存

    NSFileManager *mgr = [NSFileManager defaultManager];
    
        // 缓存路径
    
        NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    
        // 删除removeItemAtPath参数中的Caches目录下的文件
    
        [mgr removeItemAtPath:caches error:nil];
    

    总结:

    • 1和2本质是一样的,因为图片缓存就是在Caches目录下的,1的底层就是通过删除Caches目录下的图片来解决图片缓存的问题,只不过没有将缓存路径暴露在外面罢了。1只能删除存在Caches目录下的图片,不能删除存在tmp目录下的视频、音频文件。

    • 2是系统自带的NSFileManager类,我们仅仅用了它其中的一个小小的功能解决图片缓存问题的,因为removeItemAtPath的参数代表的路径是Caches路径,所以实现了删除Caches目录下的图片来解决图片缓存的问题

    • 2的功能局限,清除缓存的话,只能清除存储在Caches目录下的图片缓存,2的功能强大,能删除任何路径下的缓存,但是你必须先告诉NSFileManager类,指定删除哪个路径中的文件


    图片缓存和视频、音频缓存默认的存储路径


    • 图片缓存存储在沙盒的Library/Caches目录下,如果我们没有做删除操作,图片缓存就一直存在
    • 视频、音频存储在沙盒的tmp/MediaCache目录下,我们不需要做删除操作,tmp目录下的文件也会随时删除

    相关文章

      网友评论

        本文标题:数据存储方式、沙盒路径、FMDB

        本文链接:https://www.haomeiwen.com/subject/abqtsttx.html