1. 變數
要說到變數,得先在這裡補充一個知識。每當我們定義一個類的時候,在宣告property時,總會帶上一些修飾詞,比如記憶體管理,是否原子性等,還需要帶上這個變數的資料型別,而這一些的宣告都是附帶在這個變數的屬性裡的,我們稱為property.Attributes,我們試著去獲取一個類裡變數的attributes看看裡面究竟帶有一些什麼
- 首先我們宣告一個Person類,在裡面宣告瞭三個引數,有基礎資料型別和系統的NSString型別還有自定義的Dog型別,並且我們宣告一個方法獲取到屬性的attributes並用字典的形式返回
1 2 3 4 5 6 |
interface person : NSObject @property (nonatomic,copy) NSString *name; @property (nonatomic,assign) int age; @property (nonatomic,strong) Dog *dog; - (NSDictionary *)allProperties; @end |
2.在Person的實現中,我們通過runtime來獲取到值的屬性
1 2 3 4 5 6 |
- (NSDictionary *)allProperties{ NSMutableDictionary *dict = [NSMutableDictionary dictionary]; unsigned int count = 0; objc_property_t *properties = class_copyPropertyList([self class], &count); for (NSUInteger i = 0; i |
3.當我們呼叫allProperties並且列印出這個返回的字典時 我們會得到如下的內容:
1 2 3 4 5 |
{ age = "Ti,N,V_age"; dog = "T@"Dog",&,N,V_dog"; name = "T@"NSString",C,N,V_name"; } |
大喊一聲什麼鬼,什麼i什麼N什麼C,這是什麼東西,別急別急,我們來看一個東西,要理解這些符號就要先了解蘋果定義的Type Encodings也就是型別編碼,傳送門:蘋果官方文件,官方文件2在這個文件中,蘋果對每一個變數的型別進行了編碼,對方法的型別也進行了編碼,於是我們獲取到變數的attributes時,就是經過編譯器編碼後得到的屬性。
我們參試著來看懂一個編碼的型別
dog = “T@”Dog”,&,N,V_dog”;
首先這個T@”Dog” 就是指這個變數是Dog型別,&代表的是retain的在ARC狀態下也就是strong型別,N表示的是是nonatomic的,V_dog表示這個變數的名字是dog,我們再來看一下我們的宣告,是不是覺得其實並不是那麼難看懂呢?具體需要再深入瞭解的話請查閱官方文件,這裡就不再進行贅述:
1 |
@property (nonatomic,strong) Dog *dog; |
2. YYClassInfo 中的EncodingType
2.1 列舉變數型別
開啟YYClassInfo我們發現在檔案的開頭定義了一個列舉型別,這個列舉型別大致分成了三個部分
1 2 3 4 5 |
typedef NS_OPTIONS(NSUInteger, YYEncodingType) { #1 變數的資料型別 #2 method的attributes #3 變數的attributes }; |
接下來我們看一下在YYModel裡的具體實現
1 2 3 |
typedef NS_OPTIONS(NSUInteger, YYEncodingType) { // 低八位的值: 變數的資料型別 YYEncodingTypeMask = 0xFF, /// |
這裡有個地方可能不太能一下子理解就是為什麼定義了三個Mask,分別是
YYEncodingTypeMask
YYEncodingTypeQualifierMask
YYEncodingTypePropertyMask
在列舉裡,我們可以看到YY把這個列舉型別分為三類,二進位制中,在第八位的時候,定義為變數的型別,第8~16位的時候定義為方法的attributes,第16~24位定義為屬性的attributes型別,這樣我們也就很好理解為什麼要定義三個Mask了,直接可以通過列舉值&對應的mask找到它對應的部分是哪個值,這樣是為了區分不同部分的值,我們嘗試一下自己舉個例子:
1 2 3 4 5 6 7 8 |
typedef NS_OPTIONS(NSUInteger,iKYEncodingType){ iKYEncodingTypeMask = 0xFF, iKYEncodingType1 = 1, iKYEncodingType2 = 2, iKYEncodingType3 = 3, iKYEncodingTypeQualifireMask = 0xFF00, iKYEncodingTypeQualifire1 = 1 |
然後我們定義一個變數擁有Type1 Qualifire2的屬性,然後分別想要取出它們Type和Qualifire的型別
1 2 3 4 5 6 7 8 |
typedef NS_OPTIONS(NSUInteger,iKYEncodingType){ iKYEncodingTypeMask = 0xFF, iKYEncodingType1 = 1, iKYEncodingType2 = 2, iKYEncodingType3 = 3, iKYEncodingTypeQualifireMask = 0xFF00, iKYEncodingTypeQualifire1 = 1 |
1 2 3 4 |
NSLog(@"iKYEncodingType1 %d iKYEncodingTypeQualifire2 %d",(int)iKYEncodingType1,(int)iKYEncodingTypeQualifire2); iKYEncodingType test = (iKYEncodingType1|iKYEncodingTypeQualifire2); NSLog(@"%d",(int) test); NSLog(@"iKYEncodingTypeMask %d, iKYEncodingTypeQualifireMask %d",(int)(test&iKYEncodingTypeMask), (int)(test&iKYEncodingTypeQualifireMask)); |
列印的結果:
1 2 3 |
iKYEncodingType1 1 iKYEncodingTypeQualifire2 512 513 iKYEncodingTypeMask 1, iKYEncodingTypeQualifireMask 512 |
是不是跟我們預期一樣呢?YYModel用了不同的Mask來取得不同的type的值
2.2 獲取型別的方法
這裡比較容易理解直接上程式碼註釋
1 2 3 4 5 |
// 獲得Type的 encode 返回列舉的YYEncodingType型別 YYEncodingType YYEncodingGetType(const char *typeEncoding) { // 轉換const char 為 char char *type = (char *)typeEncoding; // 如果獲取不到type或者type長度 |
最後
在中午休息的時候抽空看了一下原始碼,希望明天能分享多一些,關於runtime的部分推薦一篇文章看完基本對runtime就瞭解了