一 快速生成@property
1 當我們需要用模型去實現一個比較小的功能的時候,由于我們需要對plist文件進行轉化成模型,那么很有可能我們拿到的plist文件中的屬性很多,但是我們又因為只需要研究一個很小的功能,那么我們可以不需要將plist文件中的數據全部轉化為模型數據,我們只需要提取其中的一部分用來實現模型就可以,那么我們怎么做呢?
2 做法:展開某行,然后拷貝該行的item,然后將所有的item折起來,在將拷貝的東西復制到root上即可直接將一整個plist文件改為自己需要處理的文件,用該文件去處理一項特別小的功能.
3 但是由于plist文件中屬性太多,如果我們要創建一個模型,那么不得不寫這么多屬性,首先寫這些屬性都是無用功,沒什么技術含量,那么我們就想,有沒有什么辦法,可以一次性生成寫好的屬性,或者我們直接拷貝就可以了.那么,我們就想到了一個方法,通過一個方法,可以快速的將plist文件中的屬性生成@property的格式,我們只需要將結果拷貝,往@interface中粘貼就可以了.
4 代碼(通過一個分類就可以達到效果,如果需要就直接將分類拷貝到項目中就可以)
//快速生成@property屬性
- (void)creatPropetyCode
{
//創建可變的字符串
NSMutableString*codes = [NSMutableStringstring];
//由于plist文件外層都是字典,那么我們就遍歷字典
[selfenumerateKeysAndObjectsUsingBlock:^(id_Nonnull key,id_Nonnull value,BOOL* _Nonnull stop) {
//初始化變量,用來接收字符串的
NSString*code =nil;
//打印所有的value的類型,就知道BOOL到底是什么類型了.
//2016-03-26 23:06:50.867 03-RunTime(字典轉模型)[853:40171] __NSCFBoolean
NSLog(@"%@",[value class]);
//判斷value的類型,然后響應的憑借出不同類類型的字符串,滿足模型中定義屬性的需求
if([value isKindOfClass:[NSStringclass]]) {
code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSString *%@;",key];
}elseif([value isKindOfClass:NSClassFromString(@"__NSCFBoolean")]){
code = [NSStringstringWithFormat:@"@property (nonatomic, strong) BOOL *%@;",key];
}elseif([value isKindOfClass:[NSNumberclass]]){
code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSNumber *%@;",key];
}elseif([value isKindOfClass:[NSDictionaryclass]]){
code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSDictionary *%@;",key];
}elseif([value isKindOfClass:[NSArrayclass]]){
code = [NSStringstringWithFormat:@"@property (nonatomic, strong) NSArray *%@;",key];
}
//拼接字符串
[codes appendFormat:@"\n%@\n",code];
}];
//打印出結果
NSLog(@"%@",codes);
}
//從打印的結果來看,大部分的都能打印出來,但是類型是BOOL的卻打印不出來,我們也沒法通過判斷BOOL的類型來打印,因為BOOL就不是一個類.所以我們必須得想法辦知道BOOL的類型.
二 KVC底層實現
1 模型中的KVC方法
//KVC
[statusItem setValuesForKeysWithDictionary:dict];
2 問題:KVC底層是怎么實現通過字典對模型中的屬性賦值?
2.1 首先我么要明確KVC的使用條件:KVC的使用,必須要保證模型中的屬性名要和字典中的key一一對應,否則使用KVC運行時會報錯的.
2.2 setValuesForKeysWithDictionary:該方法本質其實就是遍歷字典中所有的key,去模型中查找對應的屬性,把值給模型屬性賦值
3 setValuesForKeysWithDictionary:該方法的底層實現原理:
//遍歷
[dict enumerateKeysAndObjectsUsingBlock:^(id_Nonnull key,id_Nonnull obj,BOOL* _Nonnull stop) {
//這行代碼才是真正給模型的屬性賦值
[s setValue:dict[@"source"] forKey:@"source"];
}];
4 遍歷字典的內部給屬性賦值遵循下面幾點條件
/*
[ssetValue:dict[@"source"]forKey:@"source"];
1.首先會去模型中查找有沒有setSource方法,直接調用set方法[ssetSource:dict[@"source"]];
2.去模型中查找有沒有source屬性,source= dict[@"source"]
3.去模型中查找有沒有_source屬性,_source= dict[@"source"]
4.調用對象的setValue:forUndefinedKey:直接報錯
*/
5 很多時候我們不需要plist文件中的所有的屬性都有作用,但是我們又想用kvc來實現給模型屬性賦值,那么我們有什么辦法呢?
5.1 由于我們都知道,如果在plist文件中的屬性和模型中的屬性并不是一一對應的關系,但是如果我們用KVC運行起來會直接報錯,打印出錯誤的結果是:setValue: forUndefinedKey:那么我們是不是想辦法不讓這錯誤提示出來呢.那么我們可以重寫系統的這個方法,里面什么都不需要做.這樣同樣能達到目的.
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
{
三 MJExtension框架的底層實現(一級轉化)
MJ框架與KVC的底層實現不同點:
1 KVC是通過遍歷字典中的所有key,然后去模型中尋找對應的屬性
2 MJ框架是通過先遍歷模型中的屬性,然后去字典中尋找對應的key,所以用MJ框架的時候,模型中的屬性和字典可以不用一一對應,同樣能達到給模型賦值的效果.
3 代碼:
//返回一個創建好的模型
+ (instancetype)modelWithDict:(NSDictionary*)dict
{
//創建一個模型
idobjc = [[selfalloc] init];
intcount =0;
/*
方法:獲取成員變量列表
參數一:class獲取哪個類成員變量列表
參數二:count成員變量總數
*/
//成員變量數組指向數組第0個元素
Ivar *ivarList = class_copyIvarList(self, &count);
//遍歷所有成員變量
for(inti =0; i < count; i++) {
//獲取成員變量
Ivar ivar = ivarList[i];
//獲取成員變量名稱(將c轉為oc)
NSString*ivarName = [NSStringstringWithUTF8String:ivar_getName(ivar)];
//成員變量名稱轉換key(將成員變量前邊的"_"截取掉)
NSString*key = [ivarName substringFromIndex:1];
//從字典中取出對應value
idvalue = dict[key];
//給模型中屬性賦值(底層會去找對應的屬性和值)
[objc setValue:value forKey:key];
}
returnobjc;
}
四 附加知識點
1 const與宏的區別
1.1 編譯的時刻不一樣: 宏:預編譯 const:編譯
1.2 編譯檢查:宏不會做編譯檢查 const會
1.3 宏的好處:宏可以定義函數和方法 const不可以
1.4 宏壞處:大量使用宏,會導致預編譯時間過長
2 const作用
2.1 用于修飾右邊變量(基本變量,指針變量)
2.2 被const修飾變量只讀
2.3 有關const的面試題
int*constp1;// p1:只讀*p1:變量
constint*p2;// p2:變量*p2:只讀
intconst*p3;// p3:變量*p3:只讀
intconst*constp4;// p4:只讀*p4:只讀
constint*constp5;// p5:只讀*p5:只讀
3 const在開發當中的使用
3.1 const替換宏,宏:常用字符串或者基本數據定義成宏 -> const
3.2 修飾方法參數,讓方法參數只讀
4 static和extern
4.1 static:
—–>1> 修飾局部變量,只要被static修飾局部變量,這個局部變量的聲明周期就會延長(整個app運行過程中都在),作用域不變
—–>2> 修飾全局變量,只要被static修飾全局變量,這個全局變量只能在當前文件下使用
—–>3> 分配時刻:程序一運行的時候就會分配內存
4.2 extern:
—–>1> 僅僅只用來聲明外部全局變量
—–>2> extern不能用來定義變量
5 static和const聯合使用
5.1 被static修飾全局變量,全局變量只能在當前文件下使用
5.2 被const修飾,只讀.
6 開發中是如何避免重復定義?
做法:只要定義全局變量,都不能再自己的類中定義,一般開發中,我們會搞一個公共的文件來定義全局變量
五 總結
以上就是今天我給大家分享的知識點,很多知識點都寫得很詳細了,如果有不懂的可以給我留言,謝謝.我明天還會持續更新新的知識點.記得關注哦!!!
Baidu Button BEGIN