• 使用Objective-C的+(void)initialize初始化static变量


    在《Objective C类方法load和initialize的区别》一文中,我介绍了Objective-C对待+(void)initialize+(void)load两个方法在编译和执行时出现的不同。而这些不同也是在使用时应该非常注意的地方。不过文章里面我没有讲这两个方法在Objective-C中究竟有什么实用价值。

    其实+(void)initialize可以视为C#,Java中的静态构造函数。有了这个方法,我们就不用像C++自己另找途径来设计静态构造函数了。不过Objective-C中又有一些很不同的地方,因为Objective-C里不能把数据成员限定为static或者const。也就是说,虽然Objective-C可以定义类方法,但是类不能有数据成员。所以也不存在静态数据成员初始化的问题。

    不过作为C语言的超集,Objective-C依然可以沿用C的一些特点了定义static的全局变量来作为类静态成员。

    举个简单的例子:

     1 //header file
     2 @interface Printer : NSObject
     3 -(void)print:(NSString *)content;
     4 @end
     5  
     6 //implementation file
     7 static int available;
     8 @implementation Printer
     9  
    10 + (void)initialize {
    11     available = 1;
    12 }
    13  
    14 - (id)init {
    15     if (available <= 0) {
    16         NSLog(@"No available printer");
    17         return nil;
    18     }
    19  
    20     if (self = [super init]) {
    21         available--;
    22     }
    23     return self;
    24 }
    25  
    26 -(void)print:(NSString *)content {
    27     NSLog(@"%@", content);
    28 }
    29  
    30 -(void)dealloc {
    31     available++;
    32     [super dealloc];
    33 }
    34  
    35 @end

    在我们的程序,我们有一个Printer类可以构造对象来打印一些内容,但是Printer不是无限,比如我们这里只有一个,于是我们就能构造出一个Printer来,如果该对象没有被释放,那么我们就无法构造出另一个来进行打印。

     1 #import <Foundation/Foundation.h>
     2 #import "Printer.h"
     3  
     4 int main(int argc, const char * argv[])
     5 {
     6     @autoreleasepool {        
     7         Printer *printer = [[Printer alloc] init];
     8         [printer print:@"Print..."];
     9         Printer *printer2 = [[Printer alloc] init];
    10         NSLog(@"%@",printer2);
    11         [printer release];
    12         printer2 = [[Printer alloc] init];
    13         NSLog(@"%@",printer2);
    14     }
    15     return 0;
    16 }
    Print...
    No available printer
    (null)

    从上边的例子,我们看出+(void)initialize方法正确的为available变量进行了初始化。

    其实,static变量也可以定义在类方法的里面,这也是个实现的方法。

     1 @implementation Printer
     2  
     3 + (int)available {
     4     static int available = 1;
     5     return available;
     6 }
     7  
     8 //other methods
     9  
    10 @end

    只是这样做有几个不便利的地方。第一,在我们的其它方法中如果想要使用available变量的时候,就不能直接写变量名,而要写成

    Printer::available();

    这样字代码就不那么简洁了。

    第二,因为Objective-C的方法是没有访问域的约束的,所有方法实际上都是public的。虽然,如果我们不在@interface中声明+ (int)available方法,编译器会在该方法被调用时给出警告,但是因为@implementation中定义了+ (int)available方法,运行时依然可以执行并得到正确的返回结果。而且还可以 NSObject的- (id)performSelector:(SEL)aSelector方法来规避警告。因此我们也就失去了静态变量的对外部的隐藏性。另一方面,因为我们还察觉到我们无法对方法内静态变量进行修改,于是又失去了类内部的共享性。

    Objective-C中对于static变量,使用最多的地方,应该还是在单例模式(Singleton Patten)。比如上边Printer类我们实际只有一个,就可以定义单例方法。

     1 @implementation Printer
     2  
     3 + (Printer *)instance {
     4     static Printer *instance = nil;
     5     if (!instance) {
     6         instance = [[Printer alloc] init];
     7     }
     8  
     9     return instance;
    10 }
    11 //other methods
    12  
    13 @end

    不过个人认为将static Printer *instance = nil;定义在方法外边作为全局变量,然后用+(void)initialize进行初始化,+ (Printer *)instance方法只返回变量会更好了。

     1 static Printer *instance = nil;
     2  
     3 @implementation Printer
     4 + (void)initialize {
     5     if (!instance) {
     6         instance = [[Printer alloc] init];
     7     }
     8 }
     9 + (Printer *)instance {    
    10     return instance;
    11 }
    12 //other methods
    13 @end

    因为对于单例的初始化有线程安全的问题,而Apple的文档中明确指出+(void)initialize调用是“in a thread-safe manner”。我们就不需要在+ (Printer *)instance考虑线程安全性问题了。

    另外,如果static变量是方法外部作为全局变量的话,那么它放在@implementaion内还是外并没有关系,编译器都把它当做C的语法进行编译,并限定该变量是该文件内可访问。所以即使把static变量定义放在某个类的@implementaion里面,假如该文件里还其他类的@implementaion,依然可以访问到该static变量。

  • 相关阅读:
    Asymptote 学习记录(1):基本的安装以及用批处理模式和交互模式绘图
    导函数的介质定理
    在新浪云上建立了一个wordpress独立博客
    数学分析原理 定理 6.10
    数学分析原理 定理 6.12
    opencvSparseMat稀疏矩阵
    基于MRSHudi构建数据湖的典型应用场景介绍
    解析云原生2.0架构设计的8大关键趋势
    全链路数据血缘在满帮的实践
    10年经验总结,华为fellow教你如何成为一名优秀的架构师?
  • 原文地址:https://www.cnblogs.com/ubersexual/p/3339787.html
Copyright © 2020-2023  润新知