1.第一問(wèn):聲明在.m頂部的宏是用來(lái)做什么的?
在瀏覽UIScrollView+YYAdd.m文件時(shí),看見一個(gè)宏定義,好奇它是做什么的?往下看吧。
//問(wèn)題路徑:
YYKit/Base/UIKit/UIScrollView+YYAdd.m
//問(wèn)題代碼
#import "UIScrollView+YYAdd.h"
#import "YYKitMacro.h"
YYSYNTH_DUMMY_CLASS(UIScrollView_YYAdd)
@implementation UIScrollView (YYAdd)
...
@end
YYSYNTH_DUMMY_CLASS這個(gè)宏是做什么的?
點(diǎn)進(jìn)去看看實(shí)現(xiàn):
/**
Add this macro before each category implementation, so we don't have to use
-all_load or -force_load to load object files from static libraries that only
contain categories and no classes.
More info: http://developer.apple.com/library/mac/#qa/qa2006/qa1490.html .
*******************************************************************************
Example:
YYSYNTH_DUMMY_CLASS(NSString_YYAdd)
*/
#ifndef YYSYNTH_DUMMY_CLASS
#define YYSYNTH_DUMMY_CLASS(_name_) \
@interface YYSYNTH_DUMMY_CLASS_ ## _name_ : NSObject @end \
@implementation YYSYNTH_DUMMY_CLASS_ ## _name_ @end
#endif
在ios開發(fā)過(guò)程中,有時(shí)候會(huì)用到第三方的靜態(tài)庫(kù)(.a文件),OC沒(méi)有為每個(gè)函數(shù)(或者方法)定義鏈接符號(hào),它只為每個(gè)類創(chuàng)建鏈接符號(hào)。這樣當(dāng)在一個(gè)靜態(tài)庫(kù)中使用類別來(lái)擴(kuò)展已有類的時(shí)候,鏈接器不知道如何把類原有的方法和類別中的方法整合起來(lái),就會(huì)導(dǎo)致你調(diào)用類別中的方法時(shí),會(huì)出現(xiàn)selector not recognized的錯(cuò)誤,從而導(dǎo)致app閃退。使用這段宏定義他可以虛擬新建一個(gè)與名字category 相同.h.m 讓編譯器 編譯通過(guò)。即可解決上面的問(wèn)題。
為什么會(huì)閃退?
Objective-C的鏈接器并不會(huì)為每個(gè)方法建立符號(hào)表,而是僅僅為類建立了符號(hào)表。這樣的話,如果靜態(tài)庫(kù)中定義了已存在的一個(gè)類的分類,鏈接器就會(huì)以為這個(gè)類已經(jīng)存在,不會(huì)把分類和核心類的代碼合起來(lái)。這樣的話,在最后的可執(zhí)行文件中,就會(huì)缺少分類里的代碼,這樣函數(shù)調(diào)用就失敗了。
接著仔細(xì)閱讀庫(kù)文件的說(shuō)明文檔,你可能會(huì)在文檔中發(fā)現(xiàn)諸如在Other Linker Flags中加入-ObjC或者-all_load這樣的解決方法。
看完這些解釋,對(duì)這個(gè)宏一知半解,好奇的我又產(chǎn)生了新的問(wèn)題:關(guān)于Xcode的Other Linker Flags
閱讀這篇文章需要了解:鏈接器做什么
另外,在Ohter Linker Flags中的可使用命令行如下:
//加了這個(gè)參數(shù)后,鏈接器就會(huì)把靜態(tài)庫(kù)中所有的Objective-C類和分類都加載到最后的可執(zhí)行文件中。
-ObjC
//會(huì)讓鏈接器把所有找到的目標(biāo)文件都加載到可執(zhí)行文件中,但是千萬(wàn)不要隨便使用這個(gè)參數(shù)!假如你使用了不止一個(gè)靜態(tài)庫(kù)文件,然后又使用了這個(gè)參數(shù),那么你很有可能會(huì)遇到ld: duplicate symbol錯(cuò)誤,因?yàn)椴煌膸?kù)文件里面可能會(huì)有相同的目標(biāo)文件,所以建議在遇到-ObjC失效的情況下使用-force_load參數(shù)。
-all_load
//所做的事情跟-all_load其實(shí)是一樣的,但是-force_load需要指定要進(jìn)行全部加載的庫(kù)文件的路徑,這樣的話,你就只是完全加載了一個(gè)庫(kù)文件,不影響其余庫(kù)文件的按需加載
-force_load
遺留問(wèn)題:
$(inherited)
2.第二問(wèn):聲明在.h的這個(gè)宏是干什么的?
同樣是在瀏覽UIScrollView+YYAdd文件,這回是在.h文件中,看見一個(gè)宏定義,我這好奇心啊。
//問(wèn)題路徑:
YYKit/Base/UIKit/UIScrollView+YYAdd.h
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIScrollView (YYAdd)
...
@end
NS_ASSUME_NONNULL_END
NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END兩個(gè)宏之間的代碼,所有指針對(duì)象都被假定為nonnull, 即不能為空,否則編輯器會(huì)報(bào)警告Null passed to a callee that requires a non-null argument。