NSUserDefaults简易封装库GVUserDefaults

平常开发我们一般用NSUserDefaults来保存一些简单的数据,比如应用程序配置,NSUserDefaults提供了一系列类似于NSDictionary方法:

- (void)setObject:(nullable id)value forKey:(NSString *)defaultName 

- (nullable id)objectForKey:(NSString *)defaultName;

- (void)removeObjectForKey:(NSString *)defaultName;

我们需要保存、查询、删除配置项的话,都需要传递key以调用NSUserDefaults的方法,如果能把取配置项的操作封装成属性操作,那用起来就方便多了,GVUserDefaults就是类似这样的封装。

一、GVUserDefaults用法:

详细用法见github链接GitHub - gangverk/GVUserDefaults: NSUserDefaults access via properties.支持功能如下:

1、通过定义setupDefaults方法设置配置项默认值

2、通过定义- (NSString *)transformKey:(NSString *)key方法设置键值的保存名称,比如你属性定义的是name,但是保存时想定义为DDName。

3、通过定义suitName方法让NSUserDefaults通过initWithSuiteName初始化,以支持App共享配置

二、GVUserDefaults实现原理

1、实现原理很简单,通过运行时动态加入属性的set和get方法来实现GVUserDefaults属性的设置和获取。standardUserDefaults->init->generateAccessorMethods. 方法generateAccessorMethods通过遍历GVUserDefaults扩展定义的属性,根据属性的类型,为每个属性生成set和get方法,代码如下:

- (void)generateAccessorMethods {

unsigned int count = 0;

objc_property_t *properties = class_copyPropertyList([self class], &count);

self.mapping = [NSMutableDictionary dictionary];

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

objc_property_t property = properties[i];

const char *name = property_getName(property);

const char *attributes = property_getAttributes(property);

char *getter = strstr(attributes, ",G");

if (getter) {

getter = strdup(getter + 2);

getter = strsep(&getter, ",");

} else {

getter = strdup(name);

}

SEL getterSel = sel_registerName(getter);

free(getter);

char *setter = strstr(attributes, ",S");

if (setter) {

setter = strdup(setter + 2);

setter = strsep(&setter, ",");

} else {

asprintf(&setter, "set%c%s:", toupper(name[0]), name + 1);

}

SEL setterSel = sel_registerName(setter);

free(setter);

NSString *key = [self defaultsKeyForPropertyNamed:name];

[self.mapping setValue:key forKey:NSStringFromSelector(getterSel)];

[self.mapping setValue:key forKey:NSStringFromSelector(setterSel)];

IMP getterImp = NULL;

IMP setterImp = NULL;

char type = attributes[1];

switch (type) {case Short:

case Long:

case LongLong:

case UnsignedChar:

case UnsignedShort:

case UnsignedInt:

case UnsignedLong:

case UnsignedLongLong:

getterImp = (IMP)longLongGetter;

setterImp = (IMP)longLongSetter;

break;

case Bool:

case Char:

getterImp = (IMP)boolGetter;

setterImp = (IMP)boolSetter;

break;

case Int:

getterImp = (IMP)integerGetter;

setterImp = (IMP)integerSetter;

break;

case Float:

getterImp = (IMP)floatGetter;

setterImp = (IMP)floatSetter;

break;

case Double:

getterImp = (IMP)doubleGetter;

setterImp = (IMP)doubleSetter;

break;

case Object:

getterImp = (IMP)objectGetter;

setterImp = (IMP)objectSetter;

break;

default:

free(properties);

[NSException raise:NSInternalInconsistencyException format:@"Unsupported type of property \"%s\" in class %@", name, self];

break;

}

char types[5];

snprintf(types, 4, "%c@:", type);

class_addMethod([self class], getterSel, getterImp, types);

snprintf(types, 5, "v@:%c", type);

class_addMethod([self class], setterSel, setterImp, types);

}

free(properties);

}

2、也可以通过消息转发机制实现属性set方法和get方法,通过覆盖+ (BOOL)resolveInstanceMethod:(SEL)sel来实现

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,841评论 0 9
  • 终于把前面的base文件夹简简单单的看了一遍,终于可以回到正片上来了,保证不烂尾。 项目天天用yymodel解析数...
    充满活力的早晨阅读 1,409评论 1 0
  • 我们常常会听说 Objective-C 是一门动态语言,那么这个「动态」表现在哪呢?我想最主要的表现就是 Obje...
    Ethan_Struggle阅读 2,237评论 0 7
  • 林徽因在中国近代史上影响很大。不论是和徐志摩的感情故事还是和梁思成先生对中国建筑方面的卓越贡献,都为众人所知。但是...
    儒媛阅读 369评论 0 0
  • 读书就像洗澡, 一个洗灵魂, 一个洗身体。 曾经无数次信誓旦旦的拿出一摞书,计划这样那样看,之后拍张照片,发到朋友...
    王少挺阅读 501评论 0 0