setValuesForKeysWithDictionary模型化字典

一、簡(jiǎn)單介紹setValuesForKeysWithDictionary

在iOS的日常開(kāi)發(fā)中,經(jīng)常用到model來(lái)明確所使用的數(shù)據(jù)模型,這樣子可視化、數(shù)據(jù)邏輯等都明顯高于字典。之前公司舊項(xiàng)目沒(méi)有使用model來(lái)模型化字典,所有的數(shù)據(jù)都是在VC中用字典來(lái)存儲(chǔ)(一個(gè)人負(fù)責(zé)的,估計(jì)是為了省事。。。可實(shí)際上感覺(jué)費(fèi)了更多的代碼和時(shí)間,同時(shí)這個(gè)是一個(gè)靜態(tài)庫(kù)項(xiàng)目,我的天,要看一個(gè)數(shù)據(jù)模型就要跑項(xiàng)目打印數(shù)據(jù),到我這里就費(fèi)勁)。
所以,將數(shù)據(jù)模型化,無(wú)論在MVC、MVVM還是我公司最近用的MVP架構(gòu)中都是十分必要的,不僅僅提供方便了其他人快速了解字典內(nèi)的數(shù)據(jù),同時(shí)也可以將數(shù)據(jù)與頁(yè)面分離。
在字典模型化下,setValuesForKeysWithDictionary簡(jiǎn)直不要太帥,沒(méi)有使用其的情況下,我們對(duì)于字典模型化,是一條條的賦值,比如:

    NSMutableDictionary * dic = [NSMutableDictionary new];
    [dic setObject:@"a" forKey:@"name"];
    [dic setObject:@"mail" forKey:@"sex"];
    
    AModel *model = [AModel new];
    model.name = dic[@"name"];
    model.sex = dic[@"sex"];

這個(gè)樣子,假如數(shù)據(jù)量大的話(huà),不僅代碼量大,為了一個(gè)這么沒(méi)有技術(shù)含量的工作浪費(fèi)大量的時(shí)間也是沒(méi)有必要的。所以,蘋(píng)果提供了setValuesForKeysWithDictionary來(lái)解決這種問(wèn)題。上面的例子,可以這樣來(lái)實(shí)現(xiàn)。

    NSMutableDictionary * dic = [NSMutableDictionary new];
    [dic setObject:@"a" forKey:@"name"];
    [dic setObject:@"mail" forKey:@"sex"];

    AModel * model = [AModel new];
    [model setValuesForKeysWithDictionary:dic];

因?yàn)樵陧?xiàng)目中使用,有多個(gè)model的情況,可以創(chuàng)建一個(gè)基類(lèi)BaseModel來(lái)管理,所有的繼承這個(gè)類(lèi),將setValuesForKeysWithDictionary放入init方法中。

#import "BaseModel.h"

@implementation BaseModel

// kvc 賦值
- (instancetype)initValueWithDictionary:(NSDictionary *)dic{
    self = [super init];
    if (self) {
        
        [self setValuesForKeysWithDictionary:dic];
    }
    return self;
}
@end

setValuesForKeysWithDictionary非常好用,不需要你來(lái)一一的給對(duì)象賦值而直接從字典初始化即可,注意的是模型與字典的key值必須對(duì)應(yīng)。用的不好會(huì)經(jīng)常崩潰!我們可以來(lái)看一下兩種情況:

1、字典中無(wú)而model中有的數(shù)據(jù)

   //model 有name sex mobile
    NSMutableDictionary * dic = [NSMutableDictionary new];
    [dic setObject:@"a" forKey:@"name"];
    [dic setObject:@"mail" forKey:@"sex"];
    
    AModel *model = [[AModel alloc] initValueWithDictionary:dic];

正常運(yùn)行,model中的mobile打印出來(lái)是 null。

2、字典中有model中沒(méi)有的數(shù)據(jù)

    //model 只有name sex
    NSMutableDictionary * dic = [NSMutableDictionary new];
    [dic setObject:@"a" forKey:@"name"];
    [dic setObject:@"mail" forKey:@"sex"];
    [dic setObject:@"廈門(mén)" forKey:@"address"];

    AModel *model = [[AModel alloc] initValueWithDictionary:dic];

這種情況會(huì)崩潰,錯(cuò)誤

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<AModel 0x17403e280> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key address.'
出錯(cuò)打印.png

這種情況是因?yàn)椋瑂etValuesForKeysWithDictionary在模型中找不到對(duì)應(yīng)的key--address 來(lái)進(jìn)行賦值處理,所以出錯(cuò)崩潰。

這種情況其實(shí)很好解決,利用:

- (void)setValue:(id)value forUndefinedKey:(NSString *)key;

在model.m中實(shí)現(xiàn)這個(gè)方法,處理key值不存在或者是沒(méi)有對(duì)應(yīng)的情況。

//不做任何處理,即key值不存在的情況下
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    
}
//model.m中
//key值沒(méi)有對(duì)應(yīng)的情況下
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    if ([key isEqualToString:@"UserName"]) {
        self.name = value;
    }
}



//VC中的賦值
//model 有name sex mobile
    NSMutableDictionary * dic = [NSMutableDictionary new];
    [dic setObject:@"a" forKey:@"UserName"];
    [dic setObject:@"mail" forKey:@"sex"];
    [dic setObject:@"廈門(mén)" forKey:@"address"];

    AModel *model = [[AModel alloc] initValueWithDictionary:dic];

這樣子就不會(huì)出現(xiàn)了崩潰的現(xiàn)象。

二、potocol管理子類(lèi)的特殊情況。

在項(xiàng)目中model可以設(shè)立一個(gè)基類(lèi),所有的model都繼承這個(gè)類(lèi),就像我上面所說(shuō)的,因?yàn)榇蟛糠值膍odel都有這兩種行為:初始化和特殊key值處理。在基類(lèi)與子類(lèi)的關(guān)系中,我喜歡用potocol來(lái)管理差異(MVP)(個(gè)人理解:相比于子類(lèi)重寫(xiě)基類(lèi)的方法,應(yīng)該是層次更清楚,讓其他人直接明白子類(lèi)需要的實(shí)現(xiàn)的協(xié)議)。
BaseModel.h

#import <Foundation/Foundation.h>


@protocol ModelProtocol <NSObject>
@optional

- (instancetype)initValueWithDictionary:(NSDictionary *)dic;

- (void)initValue:(id)value forUndefinedKey:(NSString *)key;

@end

@interface BaseModel : NSObject<ModelProtocol>

@end

BaseModel.m

#import "BaseModel.h"

@implementation BaseModel

// kvc 賦值
- (instancetype)initValueWithDictionary:(NSDictionary *)dic{
    self = [super init];
    if (self) {
        
        [self setValuesForKeysWithDictionary:dic];
    }
    return self;
}
//沒(méi)有找到模型key
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
    if ([self respondsToSelector:@selector(initValue:forUndefinedKey:)]) {
        [self initValue:value forUndefinedKey:key];
    }
}

在子類(lèi)中,實(shí)現(xiàn)特殊key值

- (void)initValue:(id)value forUndefinedKey:(NSString *)key{
    if ([key isEqualToString:@"results"]) {
    }
}

三、子類(lèi)模型屬性是一個(gè)類(lèi)型為其他模型的數(shù)組。

model中有數(shù)組,數(shù)組內(nèi)類(lèi)型也是模型的話(huà),也可以利用:

- (void)setValue:(id)value forUndefinedKey:(NSString *)key;

來(lái)實(shí)現(xiàn)。
AModel.h

#import "BaseModel.h"
@class BModel;
@interface AModel : BaseModel

@property (nonatomic, strong) NSString * name;
@property (nonatomic, strong) NSString * sex;
@property (nonatomic, strong) NSString * mobile;

@property (nonatomic, strong) NSMutableArray<BModel *>* bArray;

@end

AModel.m

#import "AModel.h"
#import "BModel.h"
@implementation AModel

- (void)initValue:(id)value forUndefinedKey:(NSString *)key{
    if ([key isEqualToString:@"array"]) {
        if ([value isKindOfClass:[NSArray class]]) {
            for (NSDictionary *dic in value) {
                [self.bArray addObject:[[BModel alloc] initValueWithDictionary:dic]];
            }
        }
    }
}
//懶加載
-(NSMutableArray<BModel *> *)bArray{
    if (_bArray == nil) {
        _bArray = [NSMutableArray<BModel *> new];
    }
    return _bArray;
}
@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容