替换NSUserDefaults的方案

替换NSUserDefaults的方案

 

效果

 

源码

https://github.com/YouXianMing/iOS-Utilities

//
//  BaseValueStorageManager.h
//  ValueStorageManager
//
//  Created by YouXianMing on 16/3/17.
//  Copyright  2016年 YouXianMing. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "AbsEncryptingMode.h"

@interface BaseValueStorageManager : NSObject

/**
 *  Config the encryptingMode object and properties prefix, you should run this method first.
 *
 *  @param encryptingMode EncryptingMode object.
 *  @param prefix         Prefix string.
 */
+ (void)configEncryptingMode:(AbsEncryptingMode *)encryptingMode prefix:(NSString *)prefix;

/**
 *  Get the shared instance.
 *
 *  @return Shared instance.
 */
+ (instancetype)sharedInstance;

@end
//
//  BaseValueStorageManager.m
//  ValueStorageManager
//
//  Created by YouXianMing on 16/3/17.
//  Copyright  2016年 YouXianMing. All rights reserved.
//

#import "BaseValueStorageManager.h"
#import "FastCoder.h"
#import <objc/runtime.h>

static NSMutableDictionary  *_dictionary = nil;

@interface BaseValueStorageManager ()

@property (nonatomic, strong) NSArray            *baseValueStorageManagerProperties;
@property (nonatomic, strong) AbsEncryptingMode  *baseValueStorageManagerEncryptingMode;
@property (nonatomic, strong) NSString           *baseValueStorageManagerPrifixName;

@end

@implementation BaseValueStorageManager

+ (void)initialize {

    if (self == [BaseValueStorageManager class]) {

        _dictionary = [NSMutableDictionary dictionary];
    }
}

+ (void)configEncryptingMode:(AbsEncryptingMode *)encryptingMode prefix:(NSString *)prefix {

    BaseValueStorageManager *newObject              = [[[self class] alloc] init];
    newObject.baseValueStorageManagerEncryptingMode = (encryptingMode == nil ? [AbsEncryptingMode new]         : encryptingMode);
    newObject.baseValueStorageManagerPrifixName     = (prefix         == nil ? NSStringFromClass([self class]) : prefix);

    // Get all useful properties.
    NSArray        *allProperties    = [newObject allProperties];
    NSMutableArray *usefulProperties = [NSMutableArray array];
    for (int i = 0; i < allProperties.count; i++) {

        NSString *propertyName = allProperties[i];
        if ([propertyName isEqualToString:@"baseValueStorageManagerProperties"] ||
            [propertyName isEqualToString:@"baseValueStorageManagerEncryptingMode"] ||
            [propertyName isEqualToString:@"baseValueStorageManagerPrifixName"]) {

            continue;
        }

        [usefulProperties addObject:propertyName];
    }
    newObject.baseValueStorageManagerProperties = [NSArray arrayWithArray:usefulProperties];

    [_dictionary setObject:newObject forKey:NSStringFromClass([self class])];

    // Set all the properties.
    for (int i = 0; i < allProperties.count; i++) {

        NSString *key     = allProperties[i];
        NSString *ketPath = [newObject addPrifixWithString:key prifix:newObject.baseValueStorageManagerPrifixName];
        id object         = [[NSUserDefaults standardUserDefaults] objectForKey:ketPath];

        if (object) {

            object = [FastCoder objectWithData:[newObject.baseValueStorageManagerEncryptingMode decryptData:object]];
            [newObject setValue:object forKey:key];
        }
    }

    // KVO
    for (int i = 0; i < newObject.baseValueStorageManagerProperties.count; i++) {

        [newObject addObserver:newObject forKeyPath:newObject.baseValueStorageManagerProperties[i]
                       options:NSKeyValueObservingOptionNew context:nil];
    }
}

- (NSString *)addPrifixWithString:(NSString *)string prifix:(NSString *)prefix {

    return [NSString stringWithFormat:@"_%@_%@", prefix, string];
}

+ (instancetype)sharedInstance {

    return _dictionary[NSStringFromClass([self class])];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {

    BaseValueStorageManager *manager    = object;
    NSString                *newKeyPath = [manager addPrifixWithString:keyPath prifix:_baseValueStorageManagerPrifixName];
    id                       newValue   = [_baseValueStorageManagerEncryptingMode encryptData:[FastCoder dataWithRootObject:change[@"new"]]];
    [[NSUserDefaults standardUserDefaults] setObject:newValue forKey:newKeyPath];
}

/**
 *  Get all properties.
 *
 *  @return Properties array.
 */
- (NSArray *)allProperties {

    u_int count;
    objc_property_t *properties      = class_copyPropertyList([self class], &count);
    NSMutableArray  *propertiesArray = [NSMutableArray arrayWithCapacity:count];

    for (int i = 0; i<count; i++) {

        const char *propertyName = property_getName(properties[i]);
        [propertiesArray addObject:[NSString stringWithUTF8String: propertyName]];
    }

    free(properties);

    return propertiesArray;
}

- (void)dealloc {

    for (int i = 0; i < self.baseValueStorageManagerProperties.count; i++) {

        [self removeObserver:self forKeyPath:self.baseValueStorageManagerProperties[i]];
    }
}

@end

细节

时间: 2024-11-29 03:39:10

替换NSUserDefaults的方案的相关文章

Freeline - Android平台上的秒级编译方案

Freeline 技术揭秘 Freeline是什么? Freeline是蚂蚁金服旗下一站式理财平台蚂蚁聚宝团队15年10月在Android平台上的量身定做的一个基于动态替换的编译方案,5月阿里集团内部开源,稳定性方面:完善的基线对齐,进程级别异常隔离机制.性能方面:内部采用了类似Facebook的开源工具buck的多工程多任务并发思想:端口扫描,代码扫描,并发编译,并发dx,并发merge dex等策略,在多核机器上有明显加速效果,另外在class及dex,resources层面作了相应缓存策略

Android热修复升级探索——代码修复冷启动方案

前言 前面一篇文档, 我们提到热部署修复方案有诸多特点(有关热部署修复方案实现, Android热修复升级探索--追寻极致的代码热替换).其根本原理是基于native层方法的替换, 所以当类结构变化时,如新增减少类method/field在热部署模式下会受到限制. 但冷部署能突破这种约束, 可以更好地达到修复目的, 再加上冷部署在稳定性上具有的独特优势, 因此可以作为热部署的有利补充而存在. 冷启动实现方案概述 冷启动重启生效,现在一般有以下两种实现方案, 同时给出他们各自的优缺点:方案一 原理

linux下如何替换不可见的回车换行字符

问题描述 一个字符串里有换行符(不是n),比如:123456789000 我想把这个换行符替换成另外一个字符串("")得到字符串 "123456789000",在windows下是用 str.replaceAll("rn", "") 可以实现, 请问在linux下用java怎么实现啊? 问题补充:langshao 写道 解决方案 str.replaceAll("r", "").repla

复盘京东金融 2017 年元旦闰秒处置方案

丙申年,庚子月,戊子日. 西元二〇一七年元日,帝都霾,不禁杀. 从立秋到冬至,乃决大辟罪之季. 柴市牌楼前,人头涌动,听说今日要处决一重犯,大家都拿着瓜子端着茶壶出来看热闹. 十字路口上,面向南方跪着一位蓬头垢面的犯人,身披三械,背后斜插着一支亡命牌.身边一名刽子手,袒胸露乳,一身腱子肉闪着黝黑的光亮,双手端着一把鬼头刀,寒光凌厉.在重犯身后五丈远的地方,放置着一具长案,案上台布一片腥红,桌上还放着一筒火签,旁边有一个香炉,里头插着一根三寸长的檀香.桌后四仰八叉慵懒闲散躺着一位监斩官,不停用嘴吹

Android中以粗暴的方式替换全局字体

本文讲的是Android中以粗暴的方式替换全局字体,在 Android 下使用自定义字体已经是一个比较常见的需求了,最近也做了个比较深入的研究. 那么按照惯例我又要出个一篇有关 Android 修改字体相关的文章,但是写下来发现内容还挺多的,所以我决定将它们拆分一下,分几篇来详细的讲解(可能是五篇).主要会是一些常用的替换字体的方案,最后还会介绍一些全局替换的方案,当然也会包含最新的 『Fonts in XML』的方案. 期待你持续关注. 本篇是本系列的第二篇,之前已经发布的文章,有兴趣可以先看

如何将服务从经典网络迁移到VPC

背景 为了增强不同环境的隔离性.减少共享网络带来的卡顿.以及尽量避免业务规模发展后可能会遇到的安全性问题,我们计划将服务逐步迁移至阿里云 VPC 网络环境中.迁移之前,先在我们的测试环境上进行了尝试,以下是迁移的详细记录和遇到的问题. 要求 我们期望在迁移正式环境时做到无感知迁移,让终端用户感知不到服务的停顿.所以此次虽然是测试环境,为了给正式环境迁移提供更多的参考,也要尽可能地平滑,缩短停服时间. 迁移 迁移前后网络结构 我们的服务都是以 docker 容器的形式向外提供,每个容器都是无状态的

阿里HotFix2.0升级详解——技术运营小二畅谈热修复领域那些事

在阿里HotFix2.0升级详解直播中,阿里HotFix核心开发工程师悟二从热修复背景.常见的热修复方案.阿里HotFix历程及2.0的突破与创新三个方面展开了详细的演讲.分享中,他重点介绍了百川Hotfix2.X 类.SO文件.资源文件修复方案以及管理后台服务,并对百川Hotfix 2.X将来需要新增的功能也做了展望. 以下内容根据直播视频和PPT整理而成. 热修复背景 正常Bug修复流畅包括版本上线.用户安装.发现Bug.紧急修复.重新发版.用户安装六步.该流程中存在着明显的不足,首先重新发

React Native开发环境搭建

最近开始全面使用React技术栈开发,耳听得团队不久的将来有计划使用React Native开发app,迫不及待来尝试一波,首先搭建好开发环境并跑起来咱们程序界的经典程序,期间也有一些坑,在这里记录分享给大家. 索引 安装包管理工具 本人使用的是Mac环境,所以以Mac为例,对于Windows,其实差别不大. 安装Homebrew Homebrew是为Mac OS量身定制的一款集成包管理工具,我们使用它很方便的安装Node.js及切换Node.js版本. /usr/bin/ruby -e "$(

全局修改默认字体,通过反射也能做到

本文讲的是全局修改默认字体,通过反射也能做到, 本文作者:张旸在 Android 下使用自定义字体已经是一个比较常见的需求了,最近也做了个比较深入的研究. 那么按照惯例我又要出个一篇有关 Android 修改字体相关的文章,但是写下来发现内容还挺多的,所以我决定将它们拆分一下,分几篇来详细的讲解(可能是五篇).主要会是一些常用的替换字体的方案,最后还会介绍一些全局替换的方案,当然也会包含最新的 『Fonts in XML』的方案. 期待你持续关注. 本篇是本系列的第四篇,之前已经发布的文章,有兴