IOS数据本地存储的四种方式--

注:借鉴于:http://blog.csdn.net/jianjianyuer/article/details/8556024

      在IOS开发过程中,不管是做什么应用,都会碰到数据保存问题。将数据保存到本地,能够让程序更加流畅,不会出现让人厌恶的菊花状,使得用户的体验更好。下面是介绍数据保存的方式

 

 

第一、NSKeyedArchiver:采用归档的形式来保存数据。(归档——解档)———大量数据和频繁读写不合适使用

  1、归档器的作用是将任意的对象集合转换为字节流。这听起来像是NSPropertyListSerialization类采用的过程,但是它们之间有一个重要的区别。属性列表序列化只能转换一个有限集合的数据类型(大多是数量类型),而归档可以转换任意的OC对象、数据类型、数组、结构、字符串以及更多其他类型。

  2、Foundatio框架支持两种归档器。顺序归档和基于键的归档。基于键的归档器更加灵活,是应用程序开发中推荐使用的归档器 。

  3、一个面向对象程序在运行的时候,一般都创建了一个复杂的对象关系图,经常需要把这样一个复杂的对象关系图表示成字节流,这样的过程叫做          Archiving.

  4、而当从字节流中重新恢复对象关系图的过程叫做unarchive。

  5、NSCoder是archivie字节流的抽象类。

  6、对一个对象归档需要满足的条件是:该对象的类必须实现NSCoding协议

归档、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
-(int)create:(Note *)model
 
{
 
    NSString *homeDictionary = NSHomeDirectory();
 
    NSString *path = [homeDictionary stringByAppendingPathComponent:FILE_NAME];
 
    NSFileManager *fileManager = [NSFileManager defaultManager];
 
     
 
    BOOL isexists = [fileManager fileExistsAtPath:path];
 
    NSMutableArray *array = [[NSMutableArray alloc] init];
 
    [array addObject:model];
 
    
 
    //archive归档
 
    NSMutableData *theData = [NSMutableData data];
 
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:theData];
 
    [archiver encodeObject:array forKey:ARCHIVE_KEY];
 
    [archiver finishEncoding];
 
     
 
    [theData writeToFile:path atomically:YES];
 
//    [array writeToFile:path atomically:YES];
 
     
 
    return 0;
 
  
 
}

解档、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-(NSMutableArray *)findAll
 
{
 
    NSString *homeDictionary = NSHomeDirectory();
 
    NSString *path = [homeDictionary stringByAppendingPathComponent:FILE_NAME];
 
    NSMutableArray *listData = [[NSMutableArray alloc] init];
 
    NSData *theData = [NSData dataWithContentsOfFile:path];
 
     
 
    if([theData length]>0)
 
    {
 
        NSKeyedUnarchiver *archiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:theData];
 
        listData = [archiver decodeObjectForKey:ARCHIVE_KEY];
 
        [archiver finishDecoding];
 
    }
 
    return listData;
 
}

第二、NSUserDefaults

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//自动登陆用到的
 
  
 
+(id)configForKey:(NSString *)key
 
{
 
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
 
    return [defaults objectForKey:key];
 
}
 
//写入内容
 
+(void)setLoginConfig:(id)value forKey:(NSString *)key
 
{
 
    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
 
    [user setObject:value forKey:key];
 
    [user synchronize];   //及时强制写入
 
}
 
  
 
//读出内容
 
+(NSString *)getLoginConfig:(NSString *)key
 
{
 
    NSString *s = [Globle  configForKey:key];
 
    if(s==nil)
 
    {
 
        return @"";
 
    }
 
    return s;
 
  
 
}

 

第三、write写入磁盘

第一步:获得文件即将保存的路径:

NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,  NSUserDomainMask,YES);//使用C函数NSSearchPathForDirectoriesInDomains来获得沙盒中目录的全路径。该函数有三个参数,目录类型、he domain mask、布尔值。其中布尔值表示是否需要通过~扩展路径。而且第一个参数是不变的,即为NSSearchPathDirectory 。在IOS中后两个参数也是不变的,即为:NSUserDomainMask 和 YES。
NSString *ourDocumentPath =[documentPaths objectAtIndex:0];

还有一种方法是使用NSHomeDirectory函数获得sandbox的路径。具体的用法为:

NSString *sandboxPath = NSHomeDirectory();
// Once you have the full sandbox path, you can create a path from it,但是不能在sandbox的本文件层上写文件也不能创建目录,而应该是此基础上创建一个新的可写的目录,例如Documents,Library或者temp。
NSString *documentPath = [sandboxPath
            stringByAppendingPathComponent:@"Documents"];//将Documents添加到sandbox路径上,具体原因前面分析了!

这两者的区别就是:使用NSSearchPathForDirectoriesInDomains比在NSHomeDirectory后面添加Document更加安全。因为该文件目录可能在未来发送的系统上发生改变。

 

第二步:生成在该路径下的文件:

NSString *FileName=[documentDirectory stringByAppendingPathComponent:fileName];//fileName就是保存文件的文件名

第三步:往文件中写入数据:

[data writeToFile:FileName atomically:YES];//将NSData类型对象data写入文件,文件名为FileName

 

最后:从文件中读出数据:

NSData data=[NSData dataWithContentsOfFile:FileName options:0 error:NULL];//从FileName中读取出数据

第四、SQLite数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@interface BaseViewController ()
 
{
 
    sqlite3 *sqlDataBase;
 
}
 
@end
 
  
 
@implementation BaseViewController
 
  
 
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
 
{
 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 
    if (self) {
 
        // Custom initialization
 
    }
 
    return self;
 
}
 
  
 
- (void)viewDidLoad
 
{
 
    [super viewDidLoad];
 
    if ([self createOrOpen:@"test.db"]) {
 
//        [self createUserTable:sqlDataBase];
 
//        [self insertMBkey:nil];
 
        NSMutableArray *s = [NSMutableArray new];
 
        [self GetList:s];
 
        NSLog(@"%@",s);
 
    }else
 
    {
 
        NSLog(@"FAIL");
 
    }
 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
/**
 
 *该函数主要打开数据库myDataBase.sql,如果该数据库不存在,则进行创建
 
 *打开或者创建成功返回yes,否则返回false,参数dbName是数据库的名称
 
 **/
 
-(BOOL)createOrOpen:(NSString *)dbName
 
{
 
    //获取用户域覆径信息
 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectoryNSUserDomainMaskYES);
 
    NSString *documentsDirectory = [paths objectAtIndex:0];
 
    /**
 
     *Users/admin/Library/Application Support/iPhone Simulator/7.1/Applications/8E23557E-AAA6-471A-AAFE-E036BF1B7E4C/Library/Documentation
 
     *判断用户域是否有数据库dbNmae
 
     */
 
    NSString *path = [documentsDirectory stringByAppendingPathComponent:dbName];
 
    NSFileManager *fileManageer = [NSFileManager defaultManager];
 
    //如果用户域内有该数据库,则返回yes,否则返回NO
 
    BOOL find = [fileManageer fileExistsAtPath:path];
 
    if(find)   //对找到进行处理,如果找到了,并且打开了,则返回yes
 
    {
 
        //打开该数据库,如果打开失败,则返回NO,否则返回yes
 
        if(sqlite3_open([path UTF8String], &sqlDataBase)!= SQLITE_OK)
 
           {
 
               //关闭sqlDataBase,实际是释放了它
 
               sqlite3_close(sqlDataBase);
 
               return NO;
 
           }
 
           return YES;
 
    }
 
     
 
    NSLog(@"%d",sqlite3_open([path UTF8String], &sqlDataBase));
 
           //创建数据库,创建返回yes,并且打开数据库,否则返回NO
 
    if(sqlite3_open([path UTF8String], &sqlDataBase)==SQLITE_OK)
 
    {
 
        return YES;
 
    }else
 
    {
 
     //关闭sqlDataBase,实际是释放了它
 
        sqlite3_close(sqlDataBase);
 
        return NO;
 
    }
 
            
 
            
 
            
 
    return NO;
 
}
 
//在打开的数据库中创建表,其中sqldb为成功打开的数据库的sqlite3对象
 
-(BOOL)createUserTable:(sqlite3 *)sqlDataBas
 
{
 
    //设置sql语句
 
    char *sql = "create table user(id integer primary key, name text, address text, imageData BLOB, imageLen integer)";
 
    sqlite3_stmt *statement;  //这个相当于ODBC的Command对象,用于保存编译好的SQL语句
 
    //进行预处理,预处理失败返回NO
 
    if(sqlite3_prepare_v2(sqlDataBase, sql, -1, &statement, nil)!=SQLITE_OK)
 
    {
 
        return NO;
 
    }
 
    //预处理成功,进行执行创建操作
 
    int success = sqlite3_step(statement);
 
    sqlite3_finalize(statement);
 
    if(success !=SQLITE_DONE)
 
    {
 
        return NO;
 
    }
 
    return YES;
 
     
 
     
 
}
 
//向表中插入数据
 
-(void)insertMBkey:(NSString *)key
 
{
 
    BOOL isOK = NO;
 
    sqlite3_stmt *statement;
 
    static char *sql = "INSERT INTO user VALUES ('1', 'Bill', '河南', 'ssss','2')";
 
    int success = sqlite3_prepare_v2(sqlDataBase, sql, -1, &statement, NULL);
 
    if(success !=SQLITE_OK)
 
    {
 
        isOK = NO;
 
    }else
 
    {
 
        sqlite3_bind_text(statement, 1, [key UTF8String], -1, SQLITE_TRANSIENT);
 
        success = sqlite3_step(statement);
 
        sqlite3_finalize(statement);
 
    }
 
     
 
    if(success ==SQLITE_ERROR)
 
    {
 
        isOK = NO;
 
    }else
 
    {
 
        isOK=YES;
 
    }
 
     
 
    return;
 
}
 
//查询数据
 
-(void)GetList:(NSMutableArray *)KeysList
 
{
 
    BOOL  isOK = NO;
 
    sqlite3_stmt *statement;
 
    static char *sql = "select id,address from user";
 
    int success = sqlite3_prepare_v2(sqlDataBase, sql, -1, &statement, NULL);
 
    if(success !=SQLITE_OK)
 
    {
 
        isOK = NO;
 
    }else
 
    {
 
        //查询结果集中一条一条地遍历所有记录,这里的数字对应的时列值
 
        while (sqlite3_step(statement)==SQLITE_ROW) {
 
            int kid = sqlite3_column_int(statement, 0);
 
            char *key = (char  *)sqlite3_column_text(statement, 1);
 
            UserInfo *userModel = [[UserInfo alloc] init];
 
         
 
                userModel.userId =kid;
 
            if (key) {
 
              userModel.userAddress = [NSString stringWithUTF8String:key];
 
            }
 
                [KeysList addObject:userModel];
 
            sqlite3_finalize(statement);
 
        }
 
        NSLog(@"%@",KeysList);
 
        if(success==SQLITE_ERROR)
 
        {
 
            isOK = NO;
 
        }else
 
        {
 
            isOK = YES;
 
        }
 
        return;
 
    }
 
  
 
}
如果一件事情你觉得难的完不成,你可以把它分为若干步,并不断寻找合适的方法。最后你发现你会是个超人。不要给自己找麻烦,但遇到麻烦绝不怕,更不要退缩。 电工查找电路不通点的最快方法是:分段诊断排除,快速定位。你有什么启示吗? 求知若饥,虚心若愚。 当你对一个事情掌控不足的时候,你需要做的就是“梳理”,并制定相应的规章制度,并使资源各司其职。
原文地址:https://www.cnblogs.com/wvqusrtg/p/4497327.html