原文地址:http://blog.csdn.net/kmyhy/article/details/7026511
如果你的某个类需要实现单例模式,那么应该在哪里实现?你应该如何管理和控制它?不同的实现方式有不同的优缺点。
全局变量简介
它们令人害怕
全局变量对于老练的程序员来说是令人不愉快的东西。他们认为,如果程序中充斥着全局变量(本来应该是局部变量)是一种结构上的失败,程序将完全不受控制。
本文将全面介绍全局变量的声明和使用。
它们必不可少
事实上,程序中需要这些全局状态,全局变量必不可少。如果变量符合下列条件,则它应当是一个全局变量:
- 没有任何对象拥有该对象,需要管理它或者要对它负责;
- 在整个程序中,该对象只有一个;
- 它不是常量(比如字符串或者数字)。
如果这些全都符合,那么你应该使用全局变量。
如果你还不明白,那么于此相反的情况(不是全局变量)应该是:
- 接受对象管理的成员变量;
- 接受对象管理的集合的成员(们);
- 一个#define宏或者常量(常量属于编译器状态,而不是代码)
在Cocoa中,它们并不是真正的全局变量
事实上,我将提到的这些在Cocoa中所谓的全局变量并不是纯粹标准C中的全局变量,但在Cocoa中,我们完全可以用这些方法作为全局变量使用。
我将提到顶级成员对象(即application delegate的成员),以及单例对象。
并解释,为什么它们会被认为是全局对象:
- 应用程序对象是最先构造的对象,而其它对象按照不同层级先后依次构造,因此顶级对象的作用域是整个应用程序(就像一个全局对象)。应用程序委托被认为是应用程序对象的衍生(对于你永远不重载application类时尤其如此)。
- 一个单例对象只能被分配一次(并且不可被删除)——因此它是类的唯一的全局实例。单例对象其实是以全局变量的形式储存的,它们永远不会用Objective C的方式访问(它们是以类方法的方式访问的),至少在实现中提供一些抽象方法。
应用程序委托和应用程序控制器
Cocoa程序员应知道,MainMenu.xib文件中创建了一个应用程序委托对象:
对于iPhoneSDK,则在MainWindow.xib文件。
在applicationDidFinishLaunching方法中,可以初始化一个可全局访问的变量:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
myGlobalObject = [[MyGlobalObject alloc] init];
}
|
假设myGlobalObject有一个getter方法,通过这种方式你就可以访问这个对象:
[[NSApp delegate] myGlobalObject]
|
或者(iPhone中):
[[UIApplication sharedApplication].delegate myGlobalObject]
|
由于delegate返回的是id类型(而不是你真实的delegate的类型),你需要把myGlobalObject的声明为属性,并个且把delegate对象用括号括住并转换为你真正的应用程序委托类,比如:
((MyAppDelegate *)[UIApplication sharedApplication].delegate).myGlobalObject
|
当然,我看到有人在应用程序委托头文件种使用宏来定义委托对象:
#define UIAppDelegate \
((MyAppDelegate *)[UIApplication sharedApplication].delegate)
|
然后用:
UIAppDelegate.myGlobalObject
|
来访问顶层对象(记住import 该头文件).
使用应用程序委托的弊处
上面的做法是可行的,但在我的程序中,我从不在应用程序委托中做除了这些以外的事情:
- NSApplication委托方法(从applicationDidFinishLaunching:方法直到application的finalize方法)
- 不在windows菜单条中的菜单事件处理(例如“Preferences”菜单)
使用你的AppDelegate对象去管理你的全局对象是件糟糕的事情,因为你容易把太多的东西放到顶层对象中去,AppDelegate会因此庞大、结构紊乱。这有违设计模式,被称作Big Ball of Mud(一团乱泥)。
它有损程序的结构表现在两方面。首先是封装。AppDelegate只应该关注AppDelegate的内容(比如NSApplication对象和相关状态)。如果把其他对象相关的数据放到其中,就会强行干扰其他对象的自我控制。
其次是关注分离。保管、管理程序中非应用程序相关的变量不是AppDelegate的职责。一个设计良好的程序应该将类组织在完全分离、自包含的对象内,把任何对象都放到AppDelegate中违反了这一思维。
Cocoa的单例
要实现封装,应该把全局数据创建到类中作为单独的模块。通过单例达到这一目的。
Apple有一个最基本的单例实现方式:Creating a Singleton Instance.
我个人习惯于把这些单例方法放到宏中,你可以从这里下载到我的宏定义文件:
//
// SynthesizeSingleton.h
// CocoaWithLove
//
// Created by Matt Gallagher on 20/10/08.
// Copyright 2009 Matt Gallagher. All rights reserved.
//
// Permission is given to use this source code file without charge in any
// project, commercial or otherwise, entirely at your risk, with the condition
// that any redistribution (in part or whole) of source code must retain
// this copyright and permission notice. Attribution in compiled projects is
// appreciated but not required.
//
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
\
static classname *shared##classname = nil; \
\
+ (classname *)shared##classname \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [[self alloc] init]; \
} \
} \
\
return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
\
return nil; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
\
- (void)release \
{ \
} \
\
- (id)autorelease \
{ \
return self; \
}
|
如果你在类实现中导入了SynthesizeSingleton.h头文件,则你可以使用语句:
SYNTHESIZE_SINGLETON_FOR_CLASS(MyClassName);
|
将该语句置于@implementation MyClassName声明后,这样你的类自动会变成单例。
还需要加入这一句到MyClassName的头文件中:
+ (MyClassName *)sharedMyClassName;
|
这样当其他源文件导入MyClassName.h后才能找到单例的访问方法。
一旦类成为单例,你可以使用下面的语句访问单例对象:
[MyClassName sharedMyClassName];
|
注意:单例对象不需要显式地alloc和init(在第一此访问时会自动调用alloc和init),但如果你想实行初始化动作时仍然要实现默认的init方法。
单例的好处
设计良好的单例是分离的、自管理的对象。在AppDelegate中的变量与delegate对象毫无类似,一个单例只关注它自身的角色和职责。在Xcode中打开Mac OSX10.5文档,搜索shared开头的单词,可以看到苹果使用了单例模式创建“manager”对象,允许你get、set和操作程序中只创建一次的对象。
而且,单例通过方法进行访问,在某些实现中有一些抽象的实现——你可以从真单例模式转换为基于独立线程的实现,而不用改动接口部分。
结论
除非必要,不要使用全局变量。程序中绝大多数数据都有明显的非顶级对象的“父对象”。单例及顶级对象只应当包含真正属于顶级对象的数据。
Cocoa单例在有时候是有用的和有弹性的。你可以让AppDelegate保有顶级数据,但尽可能将范围限制于MainMenu.xib构造的对象。
分享到:
相关推荐
墨韵读书会的顶层数据流图 墨韵读书会的顶层数据流图 墨韵读书会的顶层数据流图 墨韵读书会的顶层数据流图 墨韵读书会的顶层数据流图 墨韵读书会的顶层数据流图 墨韵读书会的顶层数据流图 墨韵读书会的顶层数据流图 ...
顶层数据流图
针对本地区数字化业务场景、数据治理模式、数字化应用、新型数字基础设施、数 字安全体系等现状进行分析研究,并结合国家、先进城市及行业领域在数字化转型方面的相关政策要求、 发展趋势,挖掘城市数字化转型的痛点...
仓库管理系统的顶层数据流图.doc
目录 顶层数据流程图 3 中层数据流程图 4 底层数据流程图 5 顶层数据流程图 中层数据流程图 底层数据流程图 ----------------------- 物流信息系统数据流程图全文共6页,当前为第1页。 物流1117班第二组: 丁健文、...
关于数据流图简要的解释和visio数据流图案例
数字钟设计,内附顶层原理程序,好东西哦,适合初学者
【数据治理实践】第二期:顶层设计之数据战
顶层数据流图.vsdx
企业数据中台技术架构及应用解决方案共36页.pptx 企业数据中台架构及应用解决方案共25页.pptx 城市大脑新型智慧城市数据中台建设方案共31页.pptx 数据中台与数据智能应用解决方案共48页.pptx 数据中台及数据智能解决...
行政程序改革的顶层机构研究.docx
行政程序改革的顶层机构研究.doc
仓库管理系统的顶层数据流图样本.doc
据不完全统计,从2014年至今,我国涉及到大数据发展与应用的国家政策规定已多达63个,其中国家大数据发展顶层设计1个,国家层面顶层规划4个,重点行业领域发展应用31个,重点工作推进25个,重点区域发展2个。...
数据资产顶层架构设计和数据战略制定实践案例.pdf
云+网+平台+数据+应用的新型智慧城市顶层规划建设方案共53页.ppt
Android项目源码给其他应用加锁的程序锁源代码本项目是一个比较有趣的项目源码,可以给其他项目加锁,程序锁的原理是一个“看门狗”的服务定时监视顶层activity,如果activity对应的包名是之前上锁的应用程序的,则...
购物网站数据流程图 购物网站数据流程图 数据流程图数据流程图数据流程图数据流程图
电子政务云数据中心顶层设计方案 结合前期调研和XX市政府实际需求,政务云平台平台总体架构规划包括当前数据中心,同城A、B两个数据中心以及一个异地灾备中心。每个中心的定位如下: 同城A、B数据中心:两个生产中心...