前言: 這個(gè)系列可能不會(huì)分析,
Masonry
如何如何好, 估計(jì)多在分析源碼寫法, 不清楚的語法, 用了什么知識(shí)點(diǎn), 可能是這樣, 寫成什么樣也不確定,Masonry
是一個(gè)關(guān)于iOS開發(fā)的布局框架,Masonry
是對(duì)NSLayoutConstraint
的封裝, 你知道的NSLayoutConstraint
這個(gè)家伙使用起來很麻煩的, 語法相當(dāng)?shù)膯? 所以Masonry
簡(jiǎn)化了這個(gè)家伙的使用方式, 同時(shí)Masonry
有一個(gè)小兄弟, 也在成長中, 成長的也是不錯(cuò), 你可以在Masonry
的家里找到這個(gè)家伙(SnapKit), 不同的是SnapKit 是使用Siwft
寫的, 如果你都知道, 就當(dāng)是我在湊字?jǐn)?shù)(來 qq群打我好啦 認(rèn)真臉), 今天就主要介紹一些Masonry
相關(guān)的干貨, 反正你知道我是學(xué)習(xí)記錄, 談不上分享的, 我一貫就是這個(gè)態(tài)度的[囧].
下面的這張圖, 簡(jiǎn)單介紹了Masonry
的主要大部分類, 你說: 沒寫全? 對(duì)的. 我能說沒有地方畫讓我刪了嗎? 認(rèn)真.
可能會(huì)寫這樣幾篇
厚積薄發(fā)之從Masonry 源碼看Objective-C [開篇]
[厚積薄發(fā)之從Masonry 源碼看Objective-C [開篇 續(xù)]]
[厚積薄發(fā)之從Masonry 源碼看Objective-C [開篇 續(xù)續(xù)]
[厚積薄發(fā)之從Masonry 源碼看Objective-C [開篇 續(xù)續(xù)續(xù)]
[厚積薄發(fā)之從Masonry 源碼看Objective-C [終篇 - 有始有終 希望最后能夠完美]
功力有限寫什么樣, 算什么樣. 有點(diǎn)死豬不怕燙的意思. 逃跑~.
目錄
- Objective-C可變參數(shù)
- 內(nèi)聯(lián)函數(shù) inline
- mas_equalTo這個(gè)宏的實(shí)現(xiàn)
可變參數(shù): 在開始之前, 我決定先看看這個(gè)小知識(shí), 當(dāng)然你了解C 語言對(duì)此并不陌生, 然而我不像你, 我已經(jīng)把以前學(xué)的知識(shí), 交還給我的teacher了. 你可能也忘記了來跟我一起復(fù)習(xí)一遍, 在C 語言中的解釋大致是這個(gè)樣子的, 可變參數(shù)的實(shí)現(xiàn)必然不能缺少VA_LIST
,
VA_LIST 是在C語言中是這樣解釋的, 用來解決變參問題的一組宏靠胜,所在頭文件:#include <stdarg.h>,用于獲取不確定個(gè)數(shù)的參數(shù)
而在Objective-C中 同樣也有關(guān)于處理不確定參數(shù)個(gè)數(shù)的實(shí)現(xiàn)使用va_list
相關(guān), 接下來通過一段簡(jiǎn)單的代碼進(jìn)行演示.
可變參數(shù)在OC中如何實(shí)現(xiàn)?
-
va_list
定義一個(gè)va_list
變量, 這個(gè)變量的是指向參數(shù)的指針 -
va_start
使用宏 定義va_list
變量 -
va_arg
va_arg返回可變的參數(shù)峻贮,va_arg
的第二個(gè)參數(shù)是你要返回的參數(shù)的類型,如果函數(shù)有多個(gè)可變參數(shù)的,依次調(diào)用va_arg
獲取各個(gè)參數(shù) -
va_end
用va_end宏結(jié)束可變參數(shù)的獲取
- (NSMutableArray *)vaListUsing:(NSString *)p1,...NS_REQUIRES_NIL_TERMINATION{
NSMutableArray *array = [NSMutableArray array];
// 第一個(gè)參數(shù)進(jìn)數(shù)組
[array addObject:p1];
// 定義一個(gè)va_list變量, 這個(gè)變量的是指向參數(shù)的指針
va_list v;
id vStr;
// 使用宏定義va_list變量
va_start(v, p1);
// va_arg返回可變的參數(shù)结榄,va_arg的第二個(gè)參數(shù)是你要返回的參數(shù)的類型,如果函數(shù)有多個(gè)可變參數(shù)的溯职,依次調(diào)用va_arg獲取各個(gè)參數(shù)
while ((vStr = va_arg(v, id))) {
[array addObject:vStr];
}
// 用va_end宏結(jié)束可變參數(shù)的獲取
va_end(v);
return array;
}
NSMutableArray *array = [self vaListUsing:@"Cancel", @"Other",@"OK", nil];
NSLog(@"%@", array);
這是獲取的打印結(jié)果, 以上就是我通過代碼的形式表現(xiàn)出來的, 你可以通過獲取的參數(shù)名, 參數(shù)個(gè)數(shù), 可進(jìn)行適當(dāng)?shù)腢I布局什么的.
2016-11-23 15:58:09.225 Masonry閱讀理解****[5338:1112595] (*
** Cancel,**
** Other,**
** OK**
)
以上是不是跑題了, 我的回答是 并沒有! 你也相信我不能在這瞎扯淡.
接下來看看Masonry中如何使用這個(gè)小知識(shí)的呢.
在MASUtilities中
先看下面這段源碼, 通過上面的介紹, 我覺的你可能有點(diǎn)能明白了, 稍后解釋代碼, 首先看看inline
C和C++語言中inline用來聲明內(nèi)聯(lián)函數(shù)的, 我還是有些印象的 作用是是 用來替代C中表達(dá)式形式的宏定義
的. 而在OC用也是有同樣的作用.
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))
由源代碼引申之內(nèi)聯(lián)函數(shù)
定義: 內(nèi)聯(lián)函數(shù)是指用inline關(guān)鍵字修飾的函數(shù)
作用: 去掉函數(shù)調(diào)用帶來的開銷
這個(gè)說的可以 可以去看看
代碼示例
仿照Masonry的示例代碼, 我簡(jiǎn)單測(cè)試了一下, 準(zhǔn)確性有待考察, 不過粗略的看, 貌似內(nèi)聯(lián)函數(shù)效率高一點(diǎn), 你怎么看? 歡迎評(píng)論拍磚. 教我做人.
static inline
static inline int xtAdd(int x, int y){
int res = x + y;
return res;
}
#define RESXyAdd(x, y) xtAdd(x, y)
NSDate *tmpStartData = [NSDate date];
int res = RESXyAdd(2, 3);
// 內(nèi)聯(lián)
// 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
// 非內(nèi)聯(lián)
// 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的使用來解釋上面提到的代碼
首先我定義了一個(gè)View 距上左88 寬高88 我分別可以使用make.width.height.mas_equalTo(88)
make.width.height.mas_equalTo(@88)
或者 make.size.mas_equalTo(CGSizeMake(88, 88))
通過這個(gè)宏我分別可以實(shí)現(xiàn)相應(yīng)很多操作. 其實(shí)這些都是通過上面提到的內(nèi)聯(lián)函數(shù)實(shí)現(xiàn)的. 先通過strcmp
這個(gè)庫函數(shù)比較傳進(jìn)來的類型跟什么類型匹配, 之后放回相應(yīng)的對(duì)象. 完成對(duì)象的校驗(yàn). 這樣的效率很高, 同時(shí)使用方便.
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);
// 我通過這個(gè)宏 傳遞88給width 和 height
make.width.height.mas_equalTo(88);
// 或者 @88
// make.width.height.mas_equalTo(@88);
// 最終都是通過上述的內(nèi)聯(lián)函數(shù)實(shí)現(xiàn)了相應(yīng)的類型對(duì)應(yīng)
// make.size.mas_equalTo(CGSizeMake(88, 88));
}];
#
define mas_equalTo(...) equalTo(MASBoxValue((VA_ARGS)))
mas_equalTo是個(gè)上面這樣表示的宏定義
#
define MASBoxValue(value) _MASBoxValue(@encode(typeof((value))), (value))
而 MASBoxValue 最終是上面這個(gè)宏定義, 而最終 _MASBoxValue就是最上面提到的一大坨代碼(那個(gè)內(nèi)聯(lián)函數(shù)). 而不確定參數(shù), 我通過文章的開頭, 也進(jìn)行了交代.
總結(jié): 這個(gè)MASUtilities 文件 , 剩下就是一些重命名, 和宏定義的一些東西了, 這篇就到這, 篇幅太長是沒有耐心看下去的, 起個(gè)拋磚引玉的作用, 先這樣, 下一篇 還不知道怎么寫, 盡力寫的全面一點(diǎn), 讓自己有所收獲.
文/ 夏天然后