类方法的全局变量

Pat*_*ini 6 macros cocoa global-variables objective-c class-method

背景

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

[NSApplication sharedApplication]
[NSNotificationCenter defaultNotificationCenter]
[NSGraphicsContext currentContext]
[NSCalendar currentCalendar]
Run Code Online (Sandbox Code Playgroud)

等等.

他们也会偶尔使用的范例,我觉得是有大量的代码时更清晰.

NSApp //which maps to [NSApplication sharedApplication]
Run Code Online (Sandbox Code Playgroud)

目标

我希望能够在我自己的类中以及对其他类的扩展中使用这种全局变量.

MYClassInstance
NSDefaultNotificationCenter
NSCal /* or */ NSCurrentCalendar
Run Code Online (Sandbox Code Playgroud)

等等.

"duh"方法

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

Apple的方法

我能找到的唯一来源NSAppAPPKIT_EXTERN id NSApp;,这不是完全可重复使用的代码.除非我弄错了,所有这些代码确实定义NSApp为一个id世界.不幸的是没有帮助.

关闭,但不是很好

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

extern NSString * const StringConstant;
Run Code Online (Sandbox Code Playgroud)

遗憾的是,它们仅限于编译时常量,并且无法映射到必要的类方法.

底线

我希望能够推出自己NSApp风格的全局变量,这些变量映射到类方法[NSNotificationCenter defaultNotificationCenter].这可能吗?如果是这样,我应该怎么做呢?

进一步尝试

我试图通过以下方式专门实现框架单例:

MySingletons.h

//...
extern id NSNotifCenter;
//...
Run Code Online (Sandbox Code Playgroud)

MySingletons.m

//...
+(void)initialize
{
    NSNotifCenter = [NSNotificationCenter defaultCenter];
}
//...
Run Code Online (Sandbox Code Playgroud)

MyAppDelegate.m

//...
#import "MySingletons.h"
//...
//in applicationDidFinishLaunching:
    [MySingletons initialize];
    NSLog(@"%@", NSNotifCenter);
//...
Run Code Online (Sandbox Code Playgroud)

但是,这会导致无法找到_NSNotifCenter符号的编译时错误.

目标!

我目前正在开发一个Objective-C类来封装我在这个问题中提到的一些框架单例.当我拿起它时,我会在这里添加GitHub信息.

Jos*_*ell 8

这很有趣,我刚才在另一个问题上提出了这个建议.

您只需将包含单例实例的变量公开为全局变量.NSApp实际上并没有映射到一个sharedApplication电话.这是一个普通的旧指针; 它是在应用程序启动过程中设置的,指向您从该调用中返回的同一实例.

就像NSApp,您为任何导入标头的文件声明变量:

extern MySingleton * MySingletonInstance;
Run Code Online (Sandbox Code Playgroud)

在标题中(APPKIT_EXTERN如果你愿意,可以使用; 文档表明它只是extern在ObjC中解析).

在实现文件中,您可以定义变量.通常,声明保存共享实例的变量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;
Run Code Online (Sandbox Code Playgroud)
// MySingletons.m
// Dear compiler, please create this variable, reserving memory
// as necessary.
id NSNotifCenter;

@implementation MySingletons

// Now use the variable.
// etc.
Run Code Online (Sandbox Code Playgroud)

如果您正在创建单例,您可能需要浏览Apple的单例文档.