用字典给Model赋值并支持map键值替换

简介:

用字典给Model赋值并支持map键值替换

这个是昨天教程的升级版本,支持键值的map替换。

源码如下:

NSObject+Properties.h 与 NSObject+Properties.m

//
//  NSObject+Properties.h
//
//  Created by YouXianMing on 14-9-4.
//  Copyright (c) 2014年 YouXianMing. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSObject (Properties)

@property (nonatomic, strong) NSDictionary *mapDictionary;

- (void)setDataDictionary:(NSDictionary*)dataDictionary;
- (NSDictionary *)dataDictionary;

@end


//
//  NSObject+Properties.m
//
//  Created by YouXianMing on 14-9-4.
//  Copyright (c) 2014年 YouXianMing. All rights reserved.
//

#import "NSObject+Properties.h"
#import <objc/runtime.h>

@implementation NSObject (Properties)

#pragma runtime - 动态添加了一个属性,map属性
static char mapDictionaryFlag;
- (void)setMapDictionary:(NSDictionary *)mapDictionary
{
    objc_setAssociatedObject(self, &mapDictionaryFlag, mapDictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSDictionary *)mapDictionary
{
    return objc_getAssociatedObject(self, &mapDictionaryFlag);
}

#pragma public - 公开方法

- (void)setDataDictionary:(NSDictionary*)dataDictionary
{
    [self setAttributes:[self mapDictionary:self.mapDictionary dataDictionary:dataDictionary]
                    obj:self];
}

- (NSDictionary *)dataDictionary
{
    // 获取属性列表
    NSArray *properties = [self propertyNames:[self class]];
    
    // 根据属性列表获取属性值
    return [self propertiesAndValuesDictionary:self properties:properties];
}

#pragma private - 私有方法

// 通过属性名字拼凑setter方法
- (SEL)getSetterSelWithAttibuteName:(NSString*)attributeName
{
    NSString *capital = [[attributeName substringToIndex:1] uppercaseString];
    NSString *setterSelStr = \
    [NSString stringWithFormat:@"set%@%@:", capital, [attributeName substringFromIndex:1]];
    return NSSelectorFromString(setterSelStr);
}

// 通过字典设置属性值
- (void)setAttributes:(NSDictionary*)dataDic obj:(id)obj
{
    // 获取所有的key值
    NSEnumerator *keyEnum = [dataDic keyEnumerator];
    
    // 字典的key值(与Model的属性值一一对应)
    id attributeName = nil;
    while ((attributeName = [keyEnum nextObject]))
    {
        // 获取拼凑的setter方法
        SEL sel = [obj getSetterSelWithAttibuteName:attributeName];
        
        // 验证setter方法是否能回应
        if ([obj respondsToSelector:sel])
        {
            id value      = nil;
            id tmpValue   = dataDic[attributeName];
            
            if([tmpValue isKindOfClass:[NSNull class]])
            {
                // 如果是NSNull类型,则value值为空
                value = nil;
            }
            else
            {
                value = tmpValue;
            }
            
            // 执行setter方法
            [obj performSelectorOnMainThread:sel
                                  withObject:value
                               waitUntilDone:[NSThread isMainThread]];
        }
    }
}


// 获取一个类的属性名字列表
- (NSArray*)propertyNames:(Class)class
{
    NSMutableArray  *propertyNames = [[NSMutableArray alloc] init];
    unsigned int     propertyCount = 0;
    objc_property_t *properties    = class_copyPropertyList(class, &propertyCount);
    
    for (unsigned int i = 0; i < propertyCount; ++i)
    {
        objc_property_t  property = properties[i];
        const char      *name     = property_getName(property);
        
        [propertyNames addObject:[NSString stringWithUTF8String:name]];
    }
    
    free(properties);
    
    return propertyNames;
}

// 根据属性数组获取该属性的值
- (NSDictionary*)propertiesAndValuesDictionary:(id)obj properties:(NSArray *)properties
{
    NSMutableDictionary *propertiesValuesDic = [NSMutableDictionary dictionary];
    
    for (NSString *property in properties)
    {
        SEL getSel = NSSelectorFromString(property);
        
        if ([obj respondsToSelector:getSel])
        {
            NSMethodSignature  *signature  = nil;
            signature                      = [obj methodSignatureForSelector:getSel];
            NSInvocation       *invocation = [NSInvocation invocationWithMethodSignature:signature];
            [invocation setTarget:obj];
            [invocation setSelector:getSel];
            NSObject * __unsafe_unretained valueObj = nil;
            [invocation invoke];
            [invocation getReturnValue:&valueObj];
            
            //assign to @"" string
            if (valueObj == nil)
            {
                valueObj = @"";
            }
            
            propertiesValuesDic[property] = valueObj;
        }
    }
    
    return propertiesValuesDic;
}

// 根据map值替换掉键值
- (NSDictionary *)mapDictionary:(NSDictionary *)map dataDictionary:(NSDictionary *)data
{
    if (map && data)
    {
        // 拷贝字典
        NSMutableDictionary *newDataDic = [NSMutableDictionary dictionaryWithDictionary:data];
        
        // 获取所有map键值
        NSArray *allKeys                = [map allKeys];
        
        for (NSString *oldKey in allKeys)
        {
            // 获取到value
            id value = [newDataDic objectForKey:oldKey];
            
            // 如果有这个value
            if (value)
            {
                NSString *newKey = [map objectForKey:oldKey];
                [newDataDic removeObjectForKey:oldKey];
                [newDataDic setObject:value forKey:newKey];
            }
        }
        
        return newDataDic;
    }
    else
    {
        return data;
    }
}

@end

注意:

这里给NSObject的category新添加了一个属性,叫mapDictionary

然后给member添加一个属性叫做memberID

以下是使用的情况:

//
//  AppDelegate.m
//  Runtime
//
//  Created by YouXianMing on 14-9-5.
//  Copyright (c) 2014年 YouXianMing. All rights reserved.
//

#import "AppDelegate.h"
#import "NSObject+Properties.h"
#import "Model.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // 初始化model
    Model *model = [Model new];
    
    // 设置map值
    model.mapDictionary = @{@"id": @"memberID"};
    
    // 通过字典赋值
    model.dataDictionary = @{@"name"        : @"YouXianMing",
                             @"age"         : @26,
                             @"addressInfo" : @{@"HuBei": @"WeiHan"},
                             @"events"      : @[@"One", @"Two", @"Three"],
                             @"id"          : @"7788"};
    
    // 打印出属性值
    NSLog(@"%@", model.dataDictionary);
    
    return YES;
}

@end

以下就是使用流程了:

目录
相关文章
|
11月前
|
缓存 NoSQL Redis
【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构
【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构
SpringMVC入门到实战------5、域对象共享数据 Request、Session、Application、Model、ModelAndView、Map、ModelMap的详细使用及代码实例
这篇文章详细解释了在IntelliJ IDEA中如何使用Mute Breakpoints功能来快速跳过程序中的后续断点,并展示了如何一键清空所有设置的断点。
SpringMVC入门到实战------5、域对象共享数据 Request、Session、Application、Model、ModelAndView、Map、ModelMap的详细使用及代码实例
|
1月前
|
存储 前端开发 API
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用
该文章详细介绍了ES6中Set和Map数据结构的特性和使用方法,并探讨了它们在前端开发中的具体应用,包括如何利用这些数据结构来解决常见的编程问题。
ES6的Set和Map你都知道吗?一文了解集合和字典在前端中的应用
域对象共享数据model、modelAndView、map、mapModel、request。从源码角度分析
这篇文章详细解释了在IntelliJ IDEA中如何使用Mute Breakpoints功能来快速跳过程序中的后续断点,并展示了如何一键清空所有设置的断点。
域对象共享数据model、modelAndView、map、mapModel、request。从源码角度分析
|
2月前
|
存储 Go 容器
Go从入门到放弃之map(字典)
Go从入门到放弃之map(字典)
|
5月前
|
存储 C++ 容器
Map容器-构造和赋值讲解
Map容器-构造和赋值讲解
48 0
|
5月前
【SpringMVC】SpringMVC方式,向作用域对象共享数据(ModelAndView、Model、map、ModelMap)
【SpringMVC】SpringMVC方式,向作用域对象共享数据(ModelAndView、Model、map、ModelMap)
62 1
|
5月前
|
Java 机器人 开发者
使用Map批量赋值进行表单验证的实践
在Web应用程序中,表单验证是一个必不可少的环节,它可以确保用户提交的数据合法且完整。然而,传统的表单验证方法往往需要手动设置每一个验证规则,这无疑增加了开发者的负担。通过使用Map批量赋值功能,我们可以更高效地将表单数据批量赋值给验证对象,然后根据验证对象的属性进行验证。
|
10月前
|
Go
go map字典操作
go map字典操作
36 0
|
11月前
|
存储 前端开发 Java
SpringMVC里的Model、Map、ModelMap以及ModelAndView
SpringMVC里的Model、Map、ModelMap以及ModelAndView
231 0