在《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来,如果该对象没有被释放,那么我们就无法构造出另一个来进行打印。

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变量。

References:

  1. Static variable – Wikipedia
  2. What
    does “static” mean in a C program? – stackoverflow
  3. Class
    variable for Objective-C and C++ – JongAm’s blog
  4. Objective
    C Static Class Level variables – stackoverflow
  5. +
    (void)initialize – NSObject Class Reference

使用Objective-C的+(void)initialize初始化static变量的更多相关文章

  1. c++ 类与函数中static变量初始化问题(转)

    首先static变量只有一次初始化,不管在类中还是在函数中..有这样一个函数: void Foo() { ; // initialize std::cout << a; a++; } 里的 ...

  2. + (void)load和+ (void)initialize有什么用处

    两个方法都可以进行一些类的初始化操作.其中有些小区别.+(void)load 方法只要加入了工程种,进行了编译,且.m中实现了这个方法,都会调用一次,值得注意的时没实现的子类是不会调用的,就算父类实现 ...

  3. Java的初始化执行顺序(父类static变量->子类static变量->父类成员变量->父类构造器->成员变量->构造器->main函数)

    1. 引言 了解Java初始化的顺序,有助于理解Java的初始化机制和内存机制. 顺序:父类static变量->子类static变量->父类成员变量->父类构造器->成员变量- ...

  4. 把C程序的int main(void)改成static int main(void)会怎样呢?

    如题,把C程序中的主函数int main(void)改成static int main(void)会怎么样呢? 比如把 #include <stdio.h> int main(void) ...

  5. java中static变量的声明和初始化

     目录(?)[+] 问题1静态变量如何初始化 问题2JDK如何处理static块 问题3如何看待静态变量的声明 对初始问题的解答 在网上看到了下面的一段代码: public class Test  ...

  6. Objective -C Object initialization 对象初始化

    Objective -C Object initialization 对象初始化 1.1 Allocating Objects  分配对象 Allocation is the process by w ...

  7. 调整static变量初始化顺序的一个办法

    // wrap the LaunchDir variable in a function to work around static/global initialization order stati ...

  8. objective-c static变量的使用总结

    在java中,我们经常使用的是单例模式,这些设计模式在ios开发中也比较常用,最近也在考虑使用在ios开发中使用单例模式 在objective-c中,需要在.m文件里面定义个static变量来表示全局 ...

  9. 转:C语言中的static变量和C++静态数据成员(static member)

    转自:C语言中的static变量和C++静态数据成员(static member) C语言中static的变量:1).static局部变量        a.静态局部变量在函数内定义,生存期为整个程序 ...

随机推荐

  1. 77 geometry process

    0 引言 记录几何方面的一些处理技术. 1 任意多边形面积计算:包含凸多边形和凹多边形 转载了JustDoIT https://www.cnblogs.com/TenosDoIt/p/4047211. ...

  2. mysql left join 用法说明

    left join中关于where和on条件的几个知识点: 1.多表left join是会生成一张临时表,并返回给用户 2.where条件是针对最后生成的这张临时表进行过滤,过滤掉不符合where条件 ...

  3. 未来-YLB-二手市场:二手市场

    ylbtech-未来-YLB-二手市场:二手市场 1.返回顶部 1. 二手市场是人们将闲置不用的物品集中起来进行交换.交易的场所.在二手市场中买卖二手物品,价格低廉.二手交易市场又称跳蚤市场.   中 ...

  4. HBase 入门之数据刷写(Memstore Flush)详细说明

    接触过 HBase 的同学应该对 HBase 写数据的过程比较熟悉(不熟悉也没关系).HBase 写数据(比如 put.delete)的时候,都是写 WAL(假设 WAL 没有被关闭) ,然后将数据写 ...

  5. B - Heshen's Account Book HihoCoder - 1871

    题目链接:https://hihocoder.com/problemset/problem/1871 思路:满满的细节满满的坑,尤其是 123df123 居然也要算成123123 的时候真是惊呆了,我 ...

  6. js中继承的实现,原型链的知识点归纳,借用构造函数,组合继承(伪经典继承)

    博客搬迁,给你带来的不便,敬请谅解! http://www.suanliutudousi.com/2017/10/31/js%e4%b8%ad%e7%bb%a7%e6%89%bf%e7%9a%84%e ...

  7. Spring Boot集成Mybatis双数据源

    这里用到了Spring Boot + Mybatis + DynamicDataSource配置动态双数据源,可以动态切换数据源实现数据库的读写分离. 添加依赖 加入Mybatis启动器,这里添加了D ...

  8. Javascript中的相等比较

    在比较相等或不相等之前,会对操作数进行类型转换,然后比较相等性 在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则: 1.如果由一个操作数是布尔值,则在比较相等性之前先将其转换为数值:2.如果 ...

  9. Spring学习笔记(1)——初识Spring

    一.Spring是什么       通常说的Spring其实指的是Spring Framework,它是Spring下的一个子项目,Spring围绕Spring Framework这个核心项目开发了大 ...

  10. json数据扁平化处理

    json数据扁平化处理 /* * name:json数组拉平处理 * data:json对象或者数组 * k:前面开始可传空 */ function expandJsonTool(data, k) { ...