前言: 這個系列可能不會分析, 如何如何好, 估計多在分析原始碼都是如何寫的, 用了什麼知識點, 可能是這樣, 寫成什麼樣也不確定, Masonry
是一個關於iOS開發的佈局框架, Masonry
是對NSLayoutConstraint
的封裝, 你知道的NSLayoutConstraint
這個傢伙使用起來很麻煩的, 語法相當的囉嗦. 所以Masonry
簡化了這個傢伙的使用方式, 同時Masonry
有一個小兄弟, 也在成長中, 成長的也是不錯, 你可以在Masonry
的家裡找到這個傢伙(SnapKit), 不同的是SnapKit 是使用Siwft
寫的, 如果你都知道, 就當是我在湊字數(來 qq群打我好啦 認真臉), 今天就主要介紹一些Masonry
相關的乾貨, 反正你知道我是學習記錄, 談不上分享的, 我一貫就是這個態度的[囧].
下面的這張圖, 簡單介紹了Masonry
的主要大部分類, 你說: 沒寫全? 對的. 我能說沒有地方畫讓我刪了嗎? 認真.
可能會寫這樣幾篇
厚積薄發之從Masonry 原始碼看Objective-C [開篇]
厚積薄發之從Masonry 原始碼看Objective-C [開篇 續](未完成)
厚積薄發之從Masonry 原始碼看Objective-C [開篇 續續](未完成)
厚積薄發之從Masonry 原始碼看Objective-C [開篇 續續續](未完成)
厚積薄發之從Masonry 原始碼看Objective-C [終篇 – 有始有終 希望最後能夠完美](未完成)
功力有限寫什麼樣, 算什麼樣. 有點死豬不怕燙的意思. 逃跑~.
目錄
- Objective-C可變引數
- 行內函數 inline
- mas_equalTo這個巨集的實現
可變引數: 在開始之前, 我決定先看看這個小知識, 當然你瞭解C 語言對此並不陌生, 然而我不像你, 我已經把以前學的知識, 交還給我的teacher了. 你可能也忘記了來跟我一起復習一遍, 在C 語言中的解釋大致是這個樣子的, 可變引數的實現必然不能缺少VA_LIST
,
VA_LIST 是在C語言中是這樣解釋的, 用來解決變參問題的一組巨集,所在標頭檔案:#include ,用於獲取不確定個數的引數
而在Objective-C中 同樣也有關於處理不確定引數個數的實現使用va_list
相關, 接下來通過一段簡單的程式碼進行演示.
可變引數在OC中如何實現?
va_list
定義一個va_list
變數, 這個變數的是指向引數的指標va_start
使用巨集 定義va_list
變數va_arg
va_arg返回可變的引數,va_arg
的第二個引數是你要返回的引數的型別,如果函式有多個可變引數的,依次呼叫va_arg
獲取各個引數va_end
用va_end巨集結束可變引數的獲取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
- (NSMutableArray *)vaListUsing:(NSString *)p1,...NS_REQUIRES_NIL_TERMINATION{ NSMutableArray *array = [NSMutableArray array]; // 第一個引數進陣列 [array addObject:p1]; // 定義一個va_list變數, 這個變數的是指向引數的指標 va_list v; id vStr; // 使用巨集定義va_list變數 va_start(v, p1); // va_arg返回可變的引數,va_arg的第二個引數是你要返回的引數的型別,如果函式有多個可變引數的,依次呼叫va_arg獲取各個引數 while ((vStr = va_arg(v, id))) { [array addObject:vStr]; } // 用va_end巨集結束可變引數的獲取 va_end(v); return array; } |
1 2 |
NSMutableArray *array = [self vaListUsing:@"Cancel", @"Other",@"OK", nil]; NSLog(@"%@", array); |
這是獲取的列印結果, 以上就是我通過程式碼的形式表現出來的, 你可以通過獲取的引數名, 引數個數, 可進行適當的UI佈局什麼的.
2016-11-23 15:58:09.225 Masonry*閱讀理解**[5338:1112595] (
Cancel,
Other,
OK
)
以上是不是跑題了, 我的回答是 並沒有! 你也相信我不能在這瞎扯淡.
接下來看看Masonry中如何使用這個小知識的呢.
在MASUtilities中
先看下面這段原始碼, 通過上面的介紹, 我覺的你可能有點能明白了, 稍後解釋程式碼, 首先看看inline
C和C++語言中inline用來宣告行內函數的, 我還是有些印象的 作用是是 用來替代C中表示式形式的巨集定義
的. 而在OC用也是有同樣的作用.
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
static inline id _MASBoxValue(const char *type, ...) { va_list v; va_start(v, type); id obj = nil; if (strcmp(type, @encode(id)) == 0) { id actual = va_arg(v, id); obj = actual; } else if (strcmp(type, @encode(CGPoint)) == 0) { CGPoint actual = (CGPoint)va_arg(v, CGPoint); obj = [NSValue value:&actual withObjCType:type]; } else if (strcmp(type, @encode(CGSize)) == 0) { CGSize actual = (CGSize)va_arg(v, CGSize); obj = [NSValue value:&actual withObjCType:type]; } else if (strcmp(type, @encode(MASEdgeInsets)) == 0) { MASEdgeInsets actual = (MASEdgeInsets)va_arg(v, MASEdgeInsets); obj = [NSValue value:&actual withObjCType:type]; } else if (strcmp(type, @encode(double)) == 0) { double actual = (double)va_arg(v, double); obj = [NSNumber numberWithDouble:actual]; } else if (strcmp(type, @encode(float)) == 0) { float actual = (float)va_arg(v, double); obj = [NSNumber numberWithFloat:actual]; } else if (strcmp(type, @encode(int)) == 0) { int actual = (int)va_arg(v, int); obj = [NSNumber numberWithInt:actual]; } else if (strcmp(type, @encode(long)) == 0) { long actual = (long)va_arg(v, long); obj = [NSNumber numberWithLong:actual]; } else if (strcmp(type, @encode(long long)) == 0) { long long actual = (long long)va_arg(v, long long); obj = [NSNumber numberWithLongLong:actual]; } else if (strcmp(type, @encode(short)) == 0) { short actual = (short)va_arg(v, int); obj = [NSNumber numberWithShort:actual]; } else if (strcmp(type, @encode(char)) == 0) { char actual = (char)va_arg(v, int); obj = [NSNumber numberWithChar:actual]; } else if (strcmp(type, @encode(bool)) == 0) { bool actual = (bool)va_arg(v, int); obj = [NSNumber numberWithBool:actual]; } else if (strcmp(type, @encode(unsigned char)) == 0) { unsigned char actual = (unsigned char)va_arg(v, unsigned int); obj = [NSNumber numberWithUnsignedChar:actual]; } else if (strcmp(type, @encode(unsigned int)) == 0) { unsigned int actual = (unsigned int)va_arg(v, unsigned int); obj = [NSNumber numberWithUnsignedInt:actual]; } else if (strcmp(type, @encode(unsigned long)) == 0) { unsigned long actual = (unsigned long)va_arg(v, unsigned long); obj = [NSNumber numberWithUnsignedLong:actual]; } else if (strcmp(type, @encode(unsigned long long)) == 0) { unsigned long long actual = (unsigned long long)va_arg(v, unsigned long long); obj = [NSNumber numberWithUnsignedLongLong:actual]; } else if (strcmp(type, @encode(unsigned short)) == 0) { unsigned short actual = (unsigned short)va_arg(v, unsigned int); obj = [NSNumber numberWithUnsignedShort:actual]; } va_end(v); return obj; } #define MASBoxValue(value) _MASBoxValue(@encode(__typeof__((value))), (value)) |
由原始碼引申之行內函數
定義: 行內函數是指用inline關鍵字修飾的函式
作用: 去掉函式呼叫帶來的開銷
這個說的可以 可以去看看
程式碼示例
仿照Masonry的示例程式碼, 我簡單測試了一下, 準確性有待考察, 不過粗略的看, 貌似行內函數效率高一點, 你怎麼看? 歡迎評論拍磚. 教我做人.
static inline
1 2 3 4 5 |
static inline int xtAdd(int x, int y){ int res = x + y; return res; } #define RESXyAdd(x, y) xtAdd(x, y) |
1 2 3 4 5 6 7 8 9 10 11 12 |
NSDate *tmpStartData = [NSDate date]; int res = RESXyAdd(2, 3); // 內聯 // 2016-11-24 14:06:13.816 Masonry解析[7209:1504811] >>>>>>>>>>cost time = 0.608981 ms // 2016-11-24 14:00:57.229 Masonry解析[6870:1496409] >>>>>>>>>>cost time = 0.648022 ms // 2016-11-24 14:01:38.670 Masonry解析[6898:1497238] >>>>>>>>>>cost time = 0.645995 ms // 非內聯 // 2016-11-24 14:03:57.975 Masonry解析[7052:1500940] >>>>>>>>>>cost time = 0.657976 ms // 2016-11-24 14:04:57.955 Masonry解析[7101:1502351] >>>>>>>>>>cost time = 0.651002 ms NSLog(@"res === %d", res); double deltaTime = [[NSDate date] timeIntervalSinceDate:tmpStartData]; NSLog(@">>>>>>>>>>cost time = %f ms", deltaTime * 1000); |
接下來通過Masonry的使用來解釋上面提到的程式碼
首先我定義了一個View 距上左88 寬高88 我分別可以使用make.width.height.mas_equalTo(88);
make.width.height.mas_equalTo(@88);
或者 make.width.height.mas_equalTo(@88)
通過這個巨集我分別可以實現相應很多操作. 其實這些都是通過上面提到的行內函數實現的. 先通過strcmp
這個庫函式比較傳進來的型別跟什麼型別匹配, 之後放回相應的物件. 完成物件的校驗. 這樣的效率很高, 同時使用方便.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
UIView *view = [UIView new]; [self.view addSubview:view]; view.backgroundColor = [UIColor redColor]; [view mas_makeConstraints:^(MASConstraintMaker *make) { // make.top.equalTo(self.view.mas_top).with.offset(88); make.left.equalTo(self.view.mas_left).with.offset(88); // 我通過這個巨集 傳遞88給width 和 height make.width.height.mas_equalTo(88); // 或者 @88 // make.width.height.mas_equalTo(@88); // 最終都是通過上述的行內函數實現了相應的型別對應 // make.size.mas_equalTo(CGSizeMake(88, 88)); }]; |
#
define mas_equalTo(…) equalTo(MASBoxValue((VA_ARGS)))
mas_equalTo是個上面這樣表示的巨集定義
#
define MASBoxValue(value) MASBoxValue(@encode(_typeof((value))), (value))
而 MASBoxValue 最終是上面這個巨集定義, 而最終 _MASBoxValue就是最上面提到的一大坨程式碼(那個行內函數). 而不確定引數, 我通過文章的開頭, 也進行了交代.
總結: 這個MASUtilities 檔案 , 剩下就是一些重新命名, 和巨集定義的一些東西了, 這篇就到這, 篇幅太長是沒有耐心看下去的, 起個拋磚引玉的作用, 先這樣, 下一篇 還不知道怎麼寫, 盡力寫的全面一點, 讓自己有所收穫.
如果有一絲絲幫助 點個關注喜歡 又何妨??
文/ 夏天然後
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式