类方法的全局变量

时间:2011-12-14 02:04:54

标签: objective-c cocoa macros global-variables class-method

背景

在Cocoa中,Apple经常使用以下范例:

[NSApplication sharedApplication]
[NSNotificationCenter defaultNotificationCenter]
[NSGraphicsContext currentContext]
[NSCalendar currentCalendar]

等等。

在使用大量代码时,他们偶尔也会使用我认为更清晰的范例。

NSApp //which maps to [NSApplication sharedApplication]

目标

我希望能够在我自己的课程和其他课程的扩展中使用这种全局变量。

MYClassInstance
NSDefaultNotificationCenter
NSCal /* or */ NSCurrentCalendar

等等。

" duh"方法

#define。简单地#define NSCal [NSCalendar currentCalendar],但是现在我们都知道,宏是邪恶的(或者他们说的),它似乎不是正确的Cocoa方式。

Apple的方法

我能找到的关于NSApp的唯一来源是APPKIT_EXTERN id NSApp;,这不是完全可重复使用的代码。除非我弄错了,否则所有这些代码都会定义NSAppid世界。不幸的是没有用。

关闭,但不是很

在我的搜索中,我设法找到了几个关于"全局常量"的引导,但是这样的事情:

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信息。

2 个答案:

答案 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泄漏,但它们假设泄漏:只要应用程序运行,它们就需要存在。)