iOS 從main函數開始


  app程序的入口,同樣是main函數

  main函數為 int main(int argc, char * argv[]),C系語言大多都是這個樣子,argc是命令行總的參數個數,argv是參數的數組,值得一提的是argv中第一個參數為app的路徑+全名。

  然后就是main中的代碼  

  @autoreleasepool {

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

     }

  autoreleasepool自動釋放池,沒什么可說,從返回的UIApplicationMain開始分析。

  UIApplicationMain的聲明為

  UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString * __nullable principalClassName, NSString * __nullable delegateClassName);

  首先說說UIKIT_EXTERN,

  #ifdef __cplusplus

  #define UIKIT_EXTERN extern "C" __attribute__((visibility ("default")))

  #else

  #define UIKIT_EXTERN         extern __attribute__((visibility ("default")))

  #endif

  宏定義 #ifdef __cplusplus,如果宏定義了__cplusplus,則#define UIKIT_EXTERN extern "C" __attribute__((visibility ("default"))),否則

  #define UIKIT_EXTERN         extern __attribute__((visibility ("default")))

  區分在是否定義了__cplusplus,__cplusplus很直觀的翻譯cpp,也就是C++。__cplusplus標示符用來判斷程序是用c還是c++編譯程序編譯的。當編譯c++程序時,這個標示符會被定義,編譯c程序時,不會定義。接着對全句理解,如果已經宏定義了__cplusplus(也就是說當前源代碼被當作C++源代碼處理。否則當前源代碼被當中C源代碼處理),那么extern "C" __attribute__((visibility ("default")))

  extern "C"很好理解,在C++發明之初,為了兼容在當時正處主流的C語言,按照C編譯方式進行編譯的作用。可以理解為extern "C"就是告訴編譯器(也就是Xcode)在編譯的時候,要按照原來C語言的編譯方式對(全局)函數和變量進行編譯。

  C++是一種“不完全的面相對象語言”,對比C/C++ 兩種編譯方式,C++支持重載,從而使得函數的編譯方式不得不同於C的編譯,舉個栗子,有個函數,更新學生信息的void upDataStudentInfo(int, int);C方式去編譯此函數,不會對函數名進行特殊處理,編譯后的函數名為_upDataStudentInfo,反觀C++方式的編譯,為了支持重載,upDataStudentInfo函數會變成類似_upDataStudentInfo_int_int的函數名,同樣void upDataStudentInfo(float, int)會編譯成_upDataStudentInfo_float_int類似的函數名。這些都可在.obj文件中查看。此處對於C/C++混編互調的深層學習以及使用,不做分析,我只是個搞iOS的,在編譯后尋找函數名等多少也能說出些來,但實在不算熟悉,就不誤人子弟了。

  接下來就是__attribute__((visibility ("default"))),同出於C系語言,__attribute__是用來設置屬性的,包括函數、變量、類型,這里我們使用的是設置函數的屬性,__attribute__聽傳聞說是自測利器,同樣在C中,或者C++中,作為入門級的iOSer,理解就可。visibility屬性是設置將本項目的函數作為庫使用時的可見性。

設置了__attribute__((visibility ("default"))),函數的public屬性對外可見。

  so,總結成一句話,UIKIT_EXTERN就是將函數修飾為兼容以往C編譯方式的、具有extern屬性(文件外可見性)、public修飾的方法或變量庫外仍可見的屬性。

  繼續分析int UIApplicationMain(int argc, char *argv[], NSString * __nullable principalClassName, NSString * __nullable delegateClassName);

  前面兩個參數出於main,從第三個開始NSString * __nullable principalClassName,一個字符串類型的參數principalClassName,直譯為主要類,必須為UIApplication或者其子類,代表着當前app自身。並且如果此參數為nil的話,則默認為@"UIApplication"。

  第四個參數delegateClassName,代理類。在UIApplication中有個delegate的變量,delegate遵守UIApplicationDelegate協議負責程序的生命周期。UIApplication 接收到所有的系統事件和生命周期事件時,都會把事件傳遞給UIApplicationDelegate進行處理,至於為什么沒讓UIApplication自己去實現,涉及到了上帝類、框架類,過深,不講。

  綜合來說UIApplicationMain主要負責三件事

  1、從給定的類名初始化應用程序對象,也就是初始化UIApplication或者子類對象的一個實例,如果你在這里給定的是nil,那么 系統會默認UIApplication類,也就主要是這個類來控制以及協調應用程序的運行。在后續的工作中,你可以用靜態方法sharedApplication 來獲取應用程序的句柄。 

  2、從給定的應用程序委托類,初始化一個應用程序委托。並把該委托設置為應用程序的委托,這里就有如果傳入參數為nil,會調用函數訪問 Info.plist文件來尋找主nib文件,獲取應用程序委托。 

  3、啟動主事件循環,並開始接收事件。 

  end

  PS 1:再說說__nullable和__nonnull。在swift中,可以使用!和?來表示一個對象是optional的還是non-optional,如view?和view!。而在Objective-C中則沒有這一區分,view即可表示這個對象是optional,也可表示是non-optioanl。當Swift與OC混編的時候,Swift編譯器並不知道一個Objective-C對象到底是optional還是non-optional,因此這種情況下編譯器會隱式地將Objective-C的對象當成是non-optional。為了解決這個問題,蘋果在Xcode 6.3引入了一個Objective-C的新特性:nullability annotations。這一新特性的核心是兩個新的類型注釋:__nullable和__nonnull。從字面上我們可以猜到,__nullable表示對象可以是NULL或nil,而__nonnull表示對象不應該為空。當我們不遵循這一規則時,編譯器就會給出警告。

  在任何可以使用const關鍵字的地方都可以使用__nullable和__nonnull,不過這兩個關鍵字僅限於使用在指針類型上。而在方法的聲明中,我們還可以使用不帶下划線的nullable和nonnull。

  在屬性聲明中可以這樣使用:@property (nonatomic, copy, nonnull) NSString * name;

  也可以這樣使用:@property (nonatomic, copy) NSString * __nonnull name;

  NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END。在這兩個宏之間的代碼,所有簡單指針對象都被假定為nonnull。nullable的可以在兩個宏之間的代碼中單獨指定。

  PS 2:NSStringFromClass

  正常來說,

  id my = [[NSClassFromString(@"Wohenshuai") alloc] init];

  和

  id my = [[Wohenshuai alloc] init];

  是一樣的。但是,如果你的程序中並不存在Wohenshuai這個類,下面的寫法會出錯,而上面的寫法只是返回一個空對象而已。

  因此,在某些情況下,可以使用NSClassFromString來進行你不確定的類的初始化。

  NSClassFromString的好處是:

  1 弱化連接,因此並不會把沒有的Framework也link到程序中。

  2 不需要使用import,因為類是動態加載的,只要存在就可以加載。因此如果你的toolchain中沒有某個類的頭文件定義,而你確信這個類是可以用的,那么也可以用這種方法。

  類似的函數如下:

  NSClassFromString
  NSGetSizeAndAlignment
  NSLog
  NSLogv
  NSSelectorFromString
  NSStringFromClass
  NSStringFromSelector

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM