1. 程式人生 > >ios 類別和類擴充套件

ios 類別和類擴充套件

本文分為兩部分:
一:教你怎樣一部獲取成員屬性(通過NSObject+autoLogProperty分類)
二:對比KVC和runtime兩種字典轉模型的方法並抽取一個分類

一:自定義分類,列印字典轉模型的屬性宣告

+ (void)createPropertyCodeWithDict:(NSDictionary *)dict
{
    NSMutableString *strM = [NSMutableString string];

    // 遍歷字典
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull propertyName, id
_Nonnull value, BOOL * _Nonnull stop) { NSString *code; //__NSCFString <——> NSString型別 //__NSCFNumber <——> int型別 //__NSCFArray <——> NSArray型別 //__NSCFDictionary <——> NSDictionary型別 //__NSCFBoolean <——> BOOL型別 if
([value isKindOfClass:NSClassFromString(@"__NSCFString")]) { code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSString *%@;",propertyName]; }else if ([value isKindOfClass:NSClassFromString(@"__NSCFNumber")]){ code = [NSString stringWithFormat:@"@property (nonatomic, assign) int %@;"
,propertyName]; }else if ([value isKindOfClass:NSClassFromString(@"__NSCFArray")]){ code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSArray *%@;",propertyName]; }else if ([value isKindOfClass:NSClassFromString(@"__NSCFDictionary")]){ code = [NSString stringWithFormat:@"@property (nonatomic, strong) NSDictionary *%@;",propertyName]; }else if ([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){ code = [NSString stringWithFormat:@"@property (nonatomic, assign) BOOL %@;",propertyName]; } [strM appendFormat:@"\n%@\n",code]; }]; NSLog(@"%@",strM); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

1.核心思想:

 1.遍歷自定義類中的成員變數

 2.將遍歷獲取的成員變數定為value,複製給類中的ivar.

2.與KVC賦值的區別:

 KVC是呼叫`setValue: forKey: `的方法,將系統的成員變數作為value,自定義的屬性為key
 如果自定義的屬性找不到就必須要呼叫     `- (void)setValue:(id)value forUndefinedKey:(NSString *)key;`
 來處理報錯。
 但是runtime的字典轉模型是將自定義屬性生成的下劃線成員變數變為key.
 `setValuesForKeysWithDictionary:`就不會出現找不到key而報錯的問題了。

二、兩種字典轉模型的程式碼:

1.KVC方式字典轉模型

+ (StatusModel *)statusWithDict:(NSDictionary *)dict
{
    StatusModel *statusModel = [[self alloc] init];
    // KVC
    [statusModel setValuesForKeysWithDictionary:dict];
    return statusModel;
}

// 解決KVC報錯
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
//可以為空,表示不處理,也可以為做一些轉換操作
//    if ([key isEqualToString:@"XXX"]) {
//        _### = [value integerValue];
//    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.runtime字典轉模型

+ (instancetype)modelWithDict:(NSDictionary *)dict {
    id objc = [[self alloc] init];
    unsigned int count = 0;
    Ivar *ivarList = class_copyIvarList(self, &count);
    for (int i = 0; i < count; i++) {
        //獲取屬性名
        Ivar ivar = ivarList[i];

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

        //獲取key
        NSString *key = [propertyName substringFromIndex:1];   //取出下劃線_
        //獲取字典中的value
        id value = dict[key];

        //獲取成員屬性型別
        NSString *propertyType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];

        //此處為二級轉換,如果裡面的為字典型別,且屬性型別為二級模型的名字,不為NSDictionary
        if ([value isKindOfClass:[NSDictionary class]] && ![propertyType containsString:@"NS"]) { // 需要字典轉換成模型
            // 轉換成哪個型別
            // 打印出來的值為  @"@\"User\"", 擷取成User
            // 字串擷取
            NSRange range = [propertyType rangeOfString:@"\""];
            propertyType = [propertyType substringFromIndex:range.location + range.length];
            //此時變為 User\"";,藉著擷取掉後面的\""
            range = [propertyType rangeOfString:@"\""];
            propertyType = [propertyType substringToIndex:range.location];

            // 獲取需要轉換類的類物件
            Class modelClass =  NSClassFromString(propertyType);

            if (modelClass) {
                value =  [modelClass modelWithDict:value];
            }
        }
        if (value) {
            // KVC賦值:不能傳空
            [objc setValue:value forKey:key];
        }
    }
    return objc;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

3.具體使用

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"status.plist" ofType:nil];
    NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:filePath];

    //log方法屬性
    NSArray *dictArr = dict[@"statuses"];
    [[self class] createPropertyCodeWithDict:dictArr[0]];            //列印StatusModel的屬性
    [[self class] createPropertyCodeWithDict:dictArr[0][@"user"]];   //列印UserModel的屬性

    NSMutableArray *statuses = [NSMutableArray array];
    // 遍歷字典陣列
    for (NSDictionary *dict in dictArr) {
//        KVC字典轉模型,呼叫setValueForKeyWithDictionary:方法
//        StatusModel *statusModel = [StatusModel statusWithDict:dict];

//       runtime字典轉模型,呼叫分類方法
        StatusModel *statusModel = [StatusModel modelWithDict:dict];
        [statuses addObject:statusModel];
    }
    NSLog(@"%@",statuses);
    self.dataArray = statuses;
}

//懶載入dataArray
- (NSMutableArray *)dataArray
{
    if (!_dataArray) {
        _dataArray  = [NSMutableArray array];
    }
    return _dataArray;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

注意:demo中的工具類可以抽取使用



(function () {('pre.prettyprint code').each(function () {
var lines = (this).text().split(\n).length;varnumbering = $('').addClass('pre-numbering').hide();
(this).addClass(hasnumbering).parent().append(numbering);
for (i = 1; i <= lines; i++) {
numbering.append(('').text(i));
};
$numbering.fadeIn(1700);
});
});