runtime講解<四>

接着講runtime的應用,也是最重要的數組

1.字典轉模型

說的字典轉模型不少人會想到KVC,而後重寫測試

- (void)setValue:(id)value forUndefinedKey:(NSString *)key方法,爲何要重寫呢,由於kvc字典轉模型必須保證,模型中的屬性和字典中的key一一對應,若是不對應,系統就會調用spa

- (void)setValue:(id)value forUndefinedKey:(NSString *)key報錯指針

簡單回顧一下之前的作法啊,如今說說用runtime字典轉模型code

思路:利用運行時,遍歷模型中全部的屬性,根據模型的屬性名,去字典中查找key,取出對應的值,給模型的屬性賦值對象

步驟:提供一個NSObject分類,專門字典轉模型,之後全部模型均可以經過這個分類轉字符串

第三方JSONModel,mantle都是這麼幹的get

@implementation NSObject (Model)

+ (instancetype)modelWithDict:(NSDictionary *)dict
{
    // 思路:遍歷模型中全部屬性-》使用運行時

    // 0.建立對應的對象
    id objc = [[self alloc] init];

    // 1.利用runtime給對象中的成員屬性賦值

    // class_copyIvarList:獲取類中的全部成員屬性
    // Ivar:成員屬性的意思
    // 第一個參數:表示獲取哪一個類中的成員屬性
    // 第二個參數:表示這個類有多少成員屬性,傳入一個Int變量地址,會自動給這個變量賦值
    // 返回值Ivar *:指的是一個ivar數組,會把全部成員屬性放在一個數組中,經過返回的數組就能所有獲取到。
    /* 相似下面這種寫法

     Ivar ivar;
     Ivar ivar1;
     Ivar ivar2;
     // 定義一個ivar的數組a
     Ivar a[] = {ivar,ivar1,ivar2};

     // 用一個Ivar *指針指向數組第一個元素
     Ivar *ivarList = a;

     // 根據指針訪問數組第一個元素
     ivarList[0];

     */
    unsigned int count;

    // 獲取類中的全部成員屬性
    Ivar *ivarList = class_copyIvarList(self, &count);

    for (int i = 0; i < count; i++) {
        // 根據角標,從數組取出對應的成員屬性
        Ivar ivar = ivarList[i];

        // 獲取成員屬性名
        NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];

        // 處理成員屬性名->字典中的key
        // 從第一個角標開始截取
        NSString *key = [name substringFromIndex:1];

        // 根據成員屬性名去字典中查找對應的value
        id value = dict[key];

        // 二級轉換:若是字典中還有字典,也須要把對應的字典轉換成模型
        // 判斷下value是不是字典
        if ([value isKindOfClass:[NSDictionary class]]) {
            // 字典轉模型
            // 獲取模型的類對象,調用modelWithDict
            // 模型的類名已知,就是成員屬性的類型

            // 獲取成員屬性類型
           NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
          // 生成的是這種@"@\"User\"" 類型 -》 @"User"  在OC字符串中 \" -> ",\是轉義的意思,不佔用字符
            // 裁剪類型字符串
            NSRange range = [type rangeOfString:@"\""];

           type = [type substringFromIndex:range.location + range.length];

            range = [type rangeOfString:@"\""];

            // 裁剪到哪一個角標,不包括當前角標
          type = [type substringToIndex:range.location];


            // 根據字符串類名生成類對象
            Class modelClass = NSClassFromString(type);


            if (modelClass) { // 有對應的模型才須要轉

                // 把字典轉模型
                value  =  [modelClass modelWithDict:value];
            }


        }

        // 三級轉換:NSArray中也是字典,把數組中的字典轉換成模型.
        // 判斷值是不是數組
        if ([value isKindOfClass:[NSArray class]]) {
            // 判斷對應類有沒有實現字典數組轉模型數組的協議
            if ([self respondsToSelector:@selector(arrayContainModelClass)]) {

                // 轉換成id類型,就能調用任何對象的方法
                id idSelf = self;

                // 獲取數組中字典對應的模型
                NSString *type =  [idSelf arrayContainModelClass][key];

                // 生成模型
               Class classModel = NSClassFromString(type);
                NSMutableArray *arrM = [NSMutableArray array];
                // 遍歷字典數組,生成模型數組
                for (NSDictionary *dict in value) {
                    // 字典轉模型
                  id model =  [classModel modelWithDict:dict];
                    [arrM addObject:model];
                }

                // 把模型數組賦值給value
                value = arrM;

            }
        }


        if (value) { // 有值,才須要給模型的屬性賦值
            // 利用KVC給模型中的屬性賦值
            [objc setValue:value forKey:key];
        }

    }

    return objc;
}

@end

 

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    // 解析Plist文件
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"status.plist" ofType:nil];

    NSDictionary *statusDict = [NSDictionary dictionaryWithContentsOfFile:filePath];

    // 獲取字典數組
    NSArray *dictArr = statusDict[@"statuses"];

    // 自動生成模型的屬性字符串
//    [NSObject resolveDict:dictArr[0][@"user"]];


    _statuses = [NSMutableArray array];

    // 遍歷字典數組
    for (NSDictionary *dict in dictArr) {

        Status *status = [Status modelWithDict:dict];

        [_statuses addObject:status];

    }

    // 測試數據
    NSLog(@"%@ %@",_statuses,[_statuses[0] user]);


}

2.模型轉字典

給person類添加一個屬性namestring

- (NSDictionary *)getAllPropertyAndValues
{
	NSMutableDictionary *props = [NSMutableDictionary dictionary];
	unsigned int count;
   //獲取屬性列表
	objc_property_t *properties = class_copyPropertyList([Person class], &count);
	for (int i = 0; i < count; i++) {
		objc_property_t property = properties[i];
		//獲取屬性名
		NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
       //獲取屬性值
		id propertyValue = [self valueForKey:propertyName];
		if (propertyValue) {
      
			[props setObject:propertyValue forKey:propertyName];
		}
	}
	//釋放
	free(properties);
	
	return props;
}

調用看看結果it

Person *person = [[Person alloc] init];
	person.name = @"jia";
	NSLog(@"%@", [person getAllPropertyAndValues]);

相關文章
相關標籤/搜索