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