• 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

     

     

     

  • 相关阅读:
    爬虫心得
    WSL windows子系统ubuntu18.04建设自己的乌云
    WSL windwos 子系统 ubuntu18.04安装mysql
    python 163 email 554
    Centos 安装Oracle
    JS带进度 文件 重复 自动 异步上传
    xadmin 小组件默认折叠
    grep
    sed
    awk
  • 原文地址:https://www.cnblogs.com/liuguanlei/p/4827704.html
Copyright © 2020-2023  润新知