且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-08-13 13:26:57

用字典给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

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

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

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

以下是使用的情况:

//
//  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

以下就是使用流程了:

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