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

转载 2016年06月02日 09:47:45

在《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的全局变量来作为类静态成员。

举个简单的例子:

//header file
@interface Printer : NSObject
-(void)print:(NSString *)content;
@end
 
//implementation file
static int available;
@implementation Printer
 
+ (void)initialize {
    available = 1;
}
 
- (id)init {
    if (available <= 0) {
        NSLog(@"No available printer");
        return nil;
    }
 
    if (self = [super init]) {
        available--;
    }
    return self;
}
 
-(void)print:(NSString *)content {
    NSLog(@"%@", content);
}
 
-(void)dealloc {
    available++;
    [super dealloc];
}
 
@end


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

#import <Foundation/Foundation.h>
#import "Printer.h"
 
int main(int argc, const char * argv[])
{
    @autoreleasepool {        
        Printer *printer = [[Printer alloc] init];
        [printer print:@"Print..."];
        Printer *printer2 = [[Printer alloc] init];
        NSLog(@"%@",printer2);
        [printer release];
        printer2 = [[Printer alloc] init];
        NSLog(@"%@",printer2);
    }
    return 0;
}

Print...
No available printer
(null)


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

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

@implementation Printer
 
+ (int)available {
    static int available = 1;
    return available;
}
 
//other methods
 
@end

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

Printer::available();

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

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

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

@implementation Printer
 
+ (Printer *)instance {
    static Printer *instance = nil;
    if (!instance) {
        instance = [[Printer alloc] init];
    }
 
    return instance;
}
//other methods
 
@end


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

static Printer *instance = nil;
 
@implementation Printer
+ (void)initialize {
    if (!instance) {
        instance = [[Printer alloc] init];
    }
}
+ (Printer *)instance {    
    return instance;
}
//other methods
@end


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

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

举报

相关文章推荐

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

在《Objective C类方法load和initialize的区别》一文中,我介绍了Objective-C对待+(void)initialize和+(void)load两个方法在编译和执行时出现的不...

Objective-C的Initialize初始化方法

Objective-C很有趣的一个地方是,它非常非常像C。实际上,它就是C语言加上一些其他扩展和一个运行时间(runtime)。有了这个在每个Objective-C程序中都会起作用的附加运行时间,给了...

我是如何成为一名python大咖的?

人生苦短,都说必须python,那么我分享下我是如何从小白成为Python资深开发者的吧。2014年我大学刚毕业..

c# static变量的初始化

用static声明的变量或函数,都是属于类的,而不属于类对象,所以最好不要在类的构造函数中为static变量初始化(不需要初始化的就不用顾忌了,因为c#默认会给static变量初化得,比如staitc...
  • LH1963
  • LH1963
  • 2016-11-07 15:41
  • 1141

objective-c static变量的使用总结

转自:http://www.cnblogs.com/aigongsi/archive/2013/01/25/2876025.html 在java中,我们经常使用的是单例模式,这些设计模式在ios...

static变量利用常量和变量初始化的不同

局部static变量利用常量初始的情况,程序如下: #include using namespace std; int main() { int initNum = 3; for (int ...

【C++】变量(三) 变量的初始化

前面介绍了什么是变量,以及变量的命名与定义,现在我们来了解一下变量的初始化。  我们都知道,在定义一个变量时,需要明确它的类型和变量名,其实,有时候我们也要为变量设定一个初始值。这样在变量定义时就已...

初始化问题

原文链接:http://harttle.com/2015/10/05/cpp-variable-init.html 定义基本数据类型变量(单个值、数组)的同时可以指定初始值,如果未指定C++...

C++ static、const和static const类型成员变量声明以及初始化

C++ static、const和static const 以及它们的初始化 const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间。 st...

UnrealEngine4初始化流程

自古以来所有的游戏引擎都分为三个大阶段:Init,Loop,Exit。UE4也不例外。 首先找到带有入口函数的文件:Runtime/Launch/Private/XXXX/LaunchXXXX.cp...

C#变量初始化

C#变量初始化是C#强调安全性的另一个例子。简单地说,C#编译器需要用某个初始值对变量进行初始化,之后才能在操作中引用该变量。大多数现代编译器把没有初始化标记为警告,但C#编译器把它当作错误来看待。这...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)