美文网首页
6. static const and extern const

6. static const and extern const

作者: 海盗军长 | 来源:发表于2018-07-18 13:01 被阅读0次

    编写代码时经常要定义常量。
    比如:

    #define ANIMATION_DURATION 0.3
    

    上述预处理指令会把源码中的 ANIMATION_DURATION 字符串替换成 0.3 。
    不过这样定义出来的常量没有类型
    尽量避免在头文件里声明预处理指令

    比用预处理指令来定义常量更好的方式:

    static const NSTimeInterval kAnimationDuration = 0.3;
    

    用此方式定义的常量包含类型信息,其好处是清楚的描述了常量的含义。由此可知常量的类型为 NSTimeInterval 。
    注意常量的名称,若常量局限于某编译单元(.m 实现文件)之内,则在前面加字母k;若常量在类之外可见,则通常以类名为前缀,以表明其所属的类,例如 XZViewClassAnimationDuration。

    案例:

    // XZAnimatedView.h
    #import <UIKit / UIKit.h>
    
    @interface XZAnimatedView : UIView
    
    - (void)animate;
    
    @end
    
    //XZAnimatedView.m
    #import "XZAnimatedView.h"
    
    static const NSTimeInterval kAnimationDuration = 0.3;
    
    @implementation XZAnimatedView
    
    - (void)animate {
        [UIView animateWithDuration:kAnimationDuration
                                        animations:(^) {
                                              //perform animation
                                       }];
    }
    
    @end
    
    

    变量一定要同时使用 static 与 const 来声明。如果试图修改由 const 修饰符所声明的变量,那么编译器就会报错。static修饰符表示该变量只在定义此变量的编译单元(每个类的实现文件 .m 后缀名)中可见。
    编译器每收到一个编译单元,就会输出一份“目标文件”(object file)。上述代码中声明的 kAnimationDuration 变量,其作用域仅限于由 XZAnimatedView 生成的目标文件中。假如声明此变量时不加 static ,那么编译器会为它创建一个“外部符号”(external symbol)。此时,若其他编译单元也声明了同名变量,编译器就会抛出一条错误信息:

    duplicate symbol _kAnimationDuration in :
                  XZAnimatedView.o
                  XZOtherView.o
    

    实际上,一个变量既声明为 static , 又声明为 const ,那么编译器根本就不会创建符号,而是会像 #define 预处理指令一样,把所有遇到的变量都替换为常量。不过还是要记住:用这种方式定义的常量带有类型信息。

    有时候需要对外公开某个常量。比如说,你可能要在类代码中调用 NSNotificationCenter 以通知他人。用一个对象来派发通知(派发通知者声明通知),令其他欲接收通知的对象向该对象注册(接收者添加为该通知的观察者),这样就能实现此功能。派发通知时,需要使用字符串来表示此项通知的名称,而这个名字就可以声明为一个外界可见的常值变量。这样的话,注册者无须知道实际字符串值,只需以常值变量来注册自己想要接收的通知即可。

    此类常量需放在“全局符号表”中,以便可以在定义该变量的编译单元之外使用。应该这样来定义:

    // In the header file
    extern NSString *const XZStringConstant;
    
    // In the implementation file
    NSString *const XZStringConstant = @"value";
    

    这在常量在头文件中“声明”,且在实现文件中“定义”。注意 const 修饰符在常量类型中的位置。常量定义应从右向左解读,XZStringConstant 就是“一个常量,而这个常量是个指针,指向 NSString 对象。 ”

    编译器看到头文件中的 extern 关键字,就能明白如何在引入此头文件的代码中处理该常量了。这个关键字是要告诉编译器,在全局符号表中将有一个名叫 XZStringConstant 的符号。

    此类常量必须要定义,且只能定义一次,通常定义在与声明该常量的头文件相关的实现文件中。

    因为符号要放在全局符号表里,所以命名常量时一定要谨慎。
    例如:某应用程序中有个处理登录操作的类,在登录完成后会发出通知。派发通知所用的代码如下:

    //XZLoginManager.h
    #import <Foundation/Foundation.h>
    
    extern NSString *const XZLoginManagerDidLoginNotification;
    
    @interface XZLoginManager : NSObject
    - (void)login;
    @end
    
    //XZLoginManager.m
    
    #import "XZLoginManager.h"
    
    NSString *const XZLoginMangerDidLoginNotification = @"XZLoginMangerDidLoginNotification";
    
    @implementation XZLoginManger
    
    - (void)login {
      //  call p_didLogin.
    }
    
    - (void)p_didLogin {
         [ [NSNotificationCenter defaultCenter] postNotificationName:XZLoginMangerDidLoginNotification object:nil];
    }
    @end
    

    注意常量的名字。为避免名称冲突,最好是用与之相关的类名做前缀。系统框架中一般都这么做。例如 UIKit中的 UIApplicationDidEnterBackgroundNotification、UIApplicationWillEnterForegroundNotification。

    这样定义常量要优于使用 #define 预处理指令, 因为编译器会确保常量值不变。采用预处理指令定义的常量可能会无意中遭人修改,从而导致应用程序各个部分所使用的值互不相同。

    相关文章

      网友评论

          本文标题:6. static const and extern const

          本文链接:https://www.haomeiwen.com/subject/bnnlpftx.html