在Cocoa中,Apple经常使用以下范例:
[NSApplication sharedApplication]
[NSNotificationCenter defaultNotificationCenter]
[NSGraphicsContext currentContext]
[NSCalendar currentCalendar]
等等。
在使用大量代码时,他们偶尔也会使用我认为远更清晰的范例。
NSApp //which maps to [NSApplication sharedApplication]
我希望能够在我自己的课程和其他课程的扩展中使用这种全局变量。
MYClassInstance
NSDefaultNotificationCenter
NSCal /* or */ NSCurrentCalendar
等等。
#define
。简单地#define NSCal [NSCalendar currentCalendar]
,但是现在我们都知道,宏是邪恶的(或者他们说的),它似乎不是正确的Cocoa方式。
我能找到的关于NSApp
的唯一来源是APPKIT_EXTERN id NSApp;
,这不是完全可重复使用的代码。除非我弄错了,否则所有这些代码都会定义NSApp
为id
世界。不幸的是没有用。
在我的搜索中,我设法找到了几个关于"全局常量"的引导,但是这样的事情:
extern NSString * const StringConstant;
遗憾的是,仅限于编译时常量,并且无法映射到必要的类方法。
我希望能够推出自己的NSApp
式全局变量,这些变量映射到类[NSNotificationCenter defaultNotificationCenter]
等类方法。这可能吗?如果是这样,我应该怎么做呢?
我试图通过以下方式专门实现框架单例:
MySingletons.h
//...
extern id NSNotifCenter;
//...
MySingletons.m
//...
+(void)initialize
{
NSNotifCenter = [NSNotificationCenter defaultCenter];
}
//...
MyAppDelegate.m
//...
#import "MySingletons.h"
//...
//in applicationDidFinishLaunching:
[MySingletons initialize];
NSLog(@"%@", NSNotifCenter);
//...
但是,这会导致无法找到_NSNotifCenter符号的编译时错误。
我目前正在开发一个Objective-C类来封装我在这个问题中提到的一些框架单例。我在起床时会在这里添加GitHub信息。
答案 0 :(得分:8)
这很有趣,我just made this suggestion在另一个问题上。
您只需将包含单例实例的变量公开为全局变量。 NSApp
实际上并非映射到sharedApplication
来电。这是一个普通的旧指针;它是在应用程序启动过程中设置的,以指向从该调用中返回的同一实例。
就像NSApp
一样,您为任何导入标题的文件声明变量:
extern MySingleton * MySingletonInstance;
标题中的(如果您愿意,可以使用APPKIT_EXTERN
; the docs indicate它只会在ObjC中解析为extern
。
在实现文件中定义变量。通常,保存共享实例的变量被声明为static
以限制其与该文件的链接。如果删除static
,该语句将定义标题中“重新声明”的存储。
然后,像以前一样使用它。唯一需要注意的是,在第一次使用全局之前,仍需要调用单例设置方法[MySingleton sharedInstance]
,以确保它已初始化。 -applicationDidFinishLaunching:
可能是一个很好的候选人。
至于创建指向框架单例的指针,你可以将[CocoaSingleton sharedInstance]
的结果隐藏在你喜欢的任何变量中:一个想要使用它的类中的ivar,一个局部变量,或者一个全局变量你可以通过你编写的函数在程序中尽早初始化。
问题是,不能保证不会引起问题。除了NSApp
(或除非在某处记录)之外,实际上无法保证从任何给定sharedInstance
的调用中返回的对象将在结束时保持活动,有效或有用你的调用堆栈。
这可能只是偏执狂,但我建议不要这样做,除非你能找到一个保证,你感兴趣的单身人士总是返回同一个实例。否则,你可能会突然想到一个悬空的全局指针。
解决您的代码,标题中的声明不会创建变量。您仍然需要定义某处:
// MySingletons.h
// Dear compiler, There exists a variable, NSNotifCenter, whose
// storage is elsewhere. I want to use that variable in this file.
extern id NSNotifCenter;
// MySingletons.m
// Dear compiler, please create this variable, reserving memory
// as necessary.
id NSNotifCenter;
@implementation MySingletons
// Now use the variable.
// etc.
如果您要创建单身人士,可能需要浏览一下Apple's singleton documentation。
答案 1 :(得分:2)
这里现有的讨论非常有趣,我做了一些研究并发现了一些我以前从未意识到的事情:我可以#import
将我自己的项目中的头文件放入项目的.pch
文件中(预编译的头文件)。我的项目中的所有其他类文件自动
所以这是我现在正在做的一个例子。在.pch
文件中,在现有代码下方:
#import "MyIncludes.h"
在 MyIncludes.h 中有两种东西,类别和外部(后者符合Josh的建议):
extern NSString* EnglishHiddenKey;
extern NSString* IndexOfCurrentTermKey;
@interface UIColor (mycats)
+ (UIColor*) myGolden;
+ (UIColor*) myPaler;
@end
在 MyIncludes.m 中,我们提供定义以满足头文件中的所有声明。外部人员不必在任何类别中定义:
#import "MyIncludes.h"
NSString* EnglishHiddenKey = @"englishHidden";
NSString* IndexOfCurrentTermKey = @"indexOfCurrentTerm";
@implementation UIColor (mycats)
+ (UIColor*) myGolden {
return [self colorWithRed:1.000 green:0.894 blue:0.541 alpha:.900];
}
+ (UIColor*) myPaler {
return [self colorWithRed:1.000 green:0.996 blue:0.901 alpha:1.000];
}
@end
除了关于使用pch
文件获得神奇的全局可见性的部分之外,这与Josh的建议没有任何不同。我将它作为单独的答案(而不仅仅是评论)发布,因为它很长并且需要格式化,而显式代码可能会帮助某人。
(注意,没有内存管理,因为我正在使用ARC。当然,externs泄漏,但它们假设泄漏:只要应用程序运行,它们就需要存在。)