iOS缓存总结

意义

缓存的意义不必多说,在离线使用场景下让用户使用,为用户提供更好的体验,也可以提高活跃度,方便产品分析离线数据。

分类

iOS的缓存,大概有这么几种,NSUserDefaults,归档和接档,keychain,文件操作,SQLite,Coredata,Realm;接下来会分类介绍一下。

使用

1.NSUserDefaults的使用和总结
这是苹果为我们提供好的缓存策略,存储的时候以键值对key-value的形式存储,读取的时候通过key来读取,和我们熟悉的字典操作一样。下面看一段代码:

//保存
+(void)saveValue:(NSObject *)value forKey:(NSString *)key{
    [[NSUserDefaults standardUserDefaults] setObject:value forKey:key];
}

//读取
+(NSObject *)getValueForKey:(NSString *)key{
    return [[NSUserDefaults standardUserDefaults] objectForKey:key];
}

//  NSUserDefaults  使用
     NSDictionary *dict = @{
                               @"name":@"jiang",
                               @"age":@(26)};
     [UserDefaultsHandle saveValue:dict forKey:@"userInfo"];
     NSLog(@"userInfo:%@",[UserDefaultsHandle getValueForKey:@"userInfo"]);

NSUserDefaults不能存储没有遵守NSCoding协议的对象,所以如果我们想存储自己创建的对象,需要手动实现NSCoding的两个协议。

// 归档方法
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:self.name forKey:@"name"];
    [aCoder encodeObject:self.age forKey:@"age"];
    [aCoder encodeObject:self.gender forKey:@"gender"];
}
// 反归档方法
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    
    if (self != nil) {
        self.name = [aDecoder decodeObjectForKey:@"name"];
        self.age = [aDecoder decodeObjectForKey:@"age"];
        self.gender = [aDecoder decodeObjectForKey:@"gender"];
    }
    return self;
}

//使用
    Person *person = [Person new];
    person.name = @"屾铭";
    person.age = @(22);
    person.gender = @"男";
    NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:person];
    [UserDefaultsHandle saveValue:encodedObject forKey:@"personInfo"];
    NSLog(@"personInfo:%@",[NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)[UserDefaultsHandle getValueForKey:@"personInfo"]]);

2.归档和解档配合文件使用

    //解档 归档 配合 文件使用
    Person *person = [Person new];
    person.name = @"屾铭";
    person.age = @(22);
    person.gender = @"男";
    NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:person];
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSString *filePath = [documentPath stringByAppendingPathComponent:@"archiverFile"];
    BOOL result = [NSKeyedArchiver archiveRootObject:encodedObject toFile:filePath];
    if (result) {
        NSLog(@"归档成功:%@",filePath);
    }else
    {
        NSLog(@"归档失败");
    }
    Person *personOne = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedUnarchiver unarchiveObjectWithFile:filePath]];
    NSLog(@"%@",personOne);

3.Sqllite的使用
初始化数据库和创建表

//数据库初始化
+(SQLLiteHandle *)shareInstance{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSString *dbPath =  [(NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES))[0] stringByAppendingPathComponent:@"sqlLite.db"];
        _dataBase = [SQLLiteHandle databaseQueueWithPath:dbPath];
    });
    return _dataBase;
}
//创建表
-(void)creatTable:(NSString *)sqlString{
    [_dataBase inDatabase:^(FMDatabase *db) {
        BOOL status = [db executeUpdate:sqlString];
        if (status) {
            NSLog(@"create table success");
        }else{
            NSLog(@"create table fail");
        }
    }];
}

[[SQLLiteHandle shareInstance] creatTable:@"CREATE TABLE IF NOT EXISTS staff (staffId integer PRIMARY KEY NOT NULL,name text(128),gender text(128),age integer(128),department text(128))"];

增删改查的使用

//插入

-(BOOL)insertDataWithSqlString:(NSDictionary *)dict{
    __block BOOL status = NO;
    [_dataBase inDatabase:^(FMDatabase *db) {
        status = [db executeUpdate:@"INSERT or replace INTO staff (staffId,name,gender,age,department) VALUES (?,?,?,?,?)",dict[@"staffId"],dict[@"name"],dict[@"gender"],dict[@"age"],dict[@"department"]];
    }];
    if (status) {
        NSLog(@"insert success!");
    }else{
        NSLog(@"insert fail!");
    }
    return status;
}
    NSDictionary *dict = @{@"staffId":@(12309),
                           @"name":@"niu",
                           @"gender":@"似男非女",
                           @"age":@(26),
                           @"department":@"技术部"
                           };
    [[SQLLiteHandle shareInstance] insertDataWithSqlString:dict];
//查询
-(NSDictionary *)selectStaffWithStaffId:(NSString *)staffId{
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [_dataBase inDatabase:^(FMDatabase *db) {
        NSString *selectString = [NSString stringWithFormat:@"SELECT * FROM staff WHERE staffId = '%@'",staffId];
        FMResultSet *result = [db executeQuery:selectString];
        while ([result next]) {
            [dict setObject:result[@"staffId"] forKey:@"staffId"];
            [dict setObject:result[@"name"] forKey:@"name"];
            [dict setObject:result[@"gender"] forKey:@"gender"];
            [dict setObject:result[@"age"] forKey:@"age"];
            [dict setObject:result[@"department"] forKey:@"department"];
        }
        [result close];
    }];
    return dict;
}
    NSDictionary *dict = [[SQLLiteHandle shareInstance] selectStaffWithStaffId:@"12309"];
    if (dict) {
        NSLog(@"%@",dict);
    }
//更新
-(BOOL)updateDataWithSqlString:(NSString *)staffId
                           age:(NSNumber *)age{
    __block BOOL status = NO;
    [_dataBase inDatabase:^(FMDatabase *db) {
        NSString *updateString = [NSString stringWithFormat:@"UPDATE  staff SET age = '%@' WHERE staffId = '%@' ",age,staffId];
        status = [db executeUpdate:updateString];
    }];
    if (status) {
        NSLog(@"update success!");
    }else{
        NSLog(@"update fail!");
    }
    return status;
}
    [[SQLLiteHandle shareInstance] updateDataWithSqlString:@"12309" age:@(30)];
//删除
-(BOOL)deleteDataWithstaffId:(NSString *)staffId{
    __block BOOL status = NO;
    [_dataBase inDatabase:^(FMDatabase *db) {
        NSString *updateString = [NSString stringWithFormat:@"DELETE FROM staff WHERE staffId = '%@' ",staffId];
        status = [db executeUpdate:updateString];
    }];
    if (status) {
        NSLog(@"delete success!");
    }else{
        NSLog(@"delete fail!");
    }
    return status;
}
    [[SQLLiteHandle shareInstance] deleteDataWithstaffId:@"12309"];

4.CoreData的使用

//配置
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    // 对Magical Record的初始化
    [MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:@"Model.sqlite"];
    return YES;
}
+(void)createStudent:(NSDictionary *)dict{
    UIApplication *application = [UIApplication sharedApplication];
    __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
    
    //线程安全
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
        Student *localStudent = [Student MR_createEntityInContext:localContext];
        localStudent.studentId = 12306;
        localStudent.name = @"卖票小学生";
        localStudent.age = 66;
        localStudent.classNumber = 3;
        localStudent.gender = YES;
    } completion:^(BOOL success, NSError *error) {
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
        if (success) {
             NSLog(@"save success");
        }
    }];
}

+(void)SelectStudentWith:(NSString *)studentId{
    Student *student = [Student MR_findFirstByAttribute:@"studentId" withValue:@(12306)];
    NSLog(@"%@",student.name);
}

+(void)updateStudentWithId:(NSString *)studentId
                      name:(NSString *)name{
    Student *student = [Student MR_findFirstByAttribute:@"studentId" withValue:@(12306)];
    //线程安全
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
        Student *localStudent = [student MR_inContext:localContext];
        localStudent.name = @"卖票的博士";
    } completion:^(BOOL success, NSError *error) {
        if (success) {
            NSArray *array = [Student MR_findAll];
            NSLog(@"%@",array);
        }
    }];
}

+(void)deleteStudent:(NSString *)studentId{
    Student *student = [Student MR_findFirstByAttribute:@"studentId" withValue:@(12306)];
    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
        Student *localStudent = [student MR_inContext:localContext];
        [localStudent MR_deleteEntityInContext:localContext];
    } completion:^(BOOL success, NSError *error) {
        if (success) {
            NSArray *array = [Student MR_findAll];
            NSLog(@"%@",array);
        }
    }];
}

总结

1.简单说一下总结,NSUserDefaults属于轻量级的,存储一些轻量的数据,就是模型不会很复杂的数据,比如单个的属性什么的,NSUserDefaults本身也是一个Plist文件,而Pilst文件有xml格式的。
2.文件的操作会遍布APP的始终,要对苹果给我们的几个沙盒目录熟悉,每个目录的只能要干什么,这又可以开一篇博客了。
3.Sqlite是一种轻便关系型数据库,而且是一种跨平台的,开发之前可以共用一套表机构,和SQL语句逻辑,而且SQL有着悠久的历史,查询效率较高,这是我比较推荐的数据库选择。我在代码中直接用了FMDB来写Demo,为了兼容多线程直接用了Queue来演示。
4.CoreData是苹果在Sqlite上封装了一层,提供给我们的缓存机制,它是基于O-R-M的,可以直接操作对象,但是由于它在SQL基础上封装了一层,所以会存在效率的问题,在实体之间建立关联的时候会遇到崩溃(时间久了,无法Debug和回忆具体的过程了,见谅),不是很推荐使用,代码中为了方便在子线程中操作,直接用了MagicalRecord来演示。
5.Realm敬请期待...
欢迎大家讨论。。。---Jiang

你可能感兴趣的:(iOS缓存总结)