iOS 从main函数开始

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

猜你喜欢

转载自blog.csdn.net/pdd_1128/article/details/76975299