ios 類別和類擴充套件
阿新 • • 發佈:2018-12-26
本文分為兩部分:
一:教你怎樣一部獲取成員屬性(通過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 =
for (i = 1; i <= lines; i++) {
};
$numbering.fadeIn(1700);
});
});