且构网

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

用字典给Model赋值

更新时间:2022-08-13 13:27:03

用字典给Model赋值

用字典给Model赋值

此篇教程讲述通过runtime扩展NSObject,可以直接用字典给Model赋值,这是相当有用的技术呢。

源码:

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)

- (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 public - 公开方法

- (void)setDataDictionary:(NSDictionary*)dataDictionary
{
    [self setAttributes: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;
}

@end

测试用Model

Model.h 与 Model.m

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

#import <Foundation/Foundation.h>

@interface Model : NSObject

@property (nonatomic, strong) NSString      *name;
@property (nonatomic, strong) NSNumber      *age;
@property (nonatomic, strong) NSDictionary  *addressInfo;
@property (nonatomic, strong) NSArray       *events;

@end


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

#import "Model.h"

@implementation Model

@end

使用时的情形
//
//  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];
    
    // 通过字典赋值
    model.dataDictionary = @{@"name"        : @"YouXianMing",
                             @"age"         : @26,
                             @"addressInfo" : @{@"HuBei": @"WeiHan"},
                             @"events"      : @[@"One", @"Two", @"Three"]};
    
    // 打印出属性值
    NSLog(@"%@", model.dataDictionary);
    
    return YES;
}

@end

打印的信息:

2014-09-05 21:03:54.840 Runtime[553:60b] {

    addressInfo =     {

        HuBei = WeiHan;

    };

    age = 26;

    events =     (

        One,

        Two,

        Three

    );

    name = YouXianMing;

}

以下是两段核心代码(符合单一职能):

用字典给Model赋值

用字典给Model赋值