根据 Mac OS X 的 Cocoa 编程,第三版, 第 202 页(第 13 章):

您将注册、阅读和 在多个类中设置默认值 您的应用程序。要确保 你总是使用同一个名字,你 应该在 单个文件,然后简单地 #import 该文件复制到您 使用名称。有几种方法 来执行此操作。例如,您可以使用 C 预处理器的 #define 命令, 但大多数 Cocoa 程序员使用 global 用于此目的的变量。

这真的是正确的最佳实践吗?全局变量?这对我来说似乎很疯狂——与我所学到的一切背道而驰。

更好的设计是定义这些定义的简单单例类吗?或者说走出去真的是正确的最佳实践吗?鉴于许多人认为单身人士是穿着漂亮衣服的全球人,还有比这两种模式更好的模式吗?

有帮助吗?

解决方案

全局变量或单身将在这里完成同样的事情。既可以用来把可可“关键”的名字,如果它拼错成一个编译器错误,不会抛出一个编译器错误。这是最主要的目的。全局变量,虽然看到它需要较少的输入更容易一些。

代替这样做的:

[myArray setObject:theObject forKey:MyGlobalVariableKeyName];

您必须做的线沿线的东西:

[myArray setObject:theObject 
            forKey:[[MySingletonVariableClass getInstance] myVariableKeyName];

全局变量是相同的效果基本上更少的打字。

其他提示

只要是明确的,推荐是创建的一成不变的全局变量,而不是在线字符串常量(难以重构,没有编译时检查)或#定义(没有编译时检查)。这里是你会如何做?

在MyConstants.h:

extern NSString * const MyStringConstant;

在MyConstants.m:

NSString * const MyStringConstant = @"MyString";

然后在任何其他.m文件:

#import "MyConstants.h"

...
[someObject someMethodTakingAString:MyStringConstant];
...

此方式,您将获得编译时检查你有没有拼写错误的字符串常量,你可以在你的比较常量检查指针平等,而不是字符串相等[1],和调试比较容易,因为常数有一个运行时的字符串值。

[1]在此使用时,实质上是使用指针值作为常数。它碰巧的是,这些特定的整数也指向可以在调试器中使用的字符串

将其称为全局变量在技术上是正确的,但具有误导性。

它是一个全局常量——作用域是全局的,但是是常量,因此从全局变量不好的意义上来说,它还不错。

展示如何全球化 常量 常见、安全​​且数量众多,请考虑以下全局常量的示例:

  • 课程中的每个课程
  • 每个#define
  • 每个枚举
  • 几乎 Cocoa 声明的每个名称(不包括罕见的全局变量,例如 NSApp).

您唯一应该担心全局常量的时候是它们的名称太通用(它们可能会污染全局命名空间)。因此,不要使用可能与任何内容冲突的名称(始终使用前缀并始终使名称特定于任务,例如 NSKeyValueObservingOptionNew).

被设置在编译时和永远不会改变

恒全局是可接受的我。如果你硬编码字符串,这是同样的事情,只是由编译器隐藏。我会避免可变全局像瘟疫。

记住,苹果本身使用相同的技术。很多我想像的要定义常量实际上常数。你会得到链接错误,如果头是可达但框架是没有的。

建筑物上@Barry沃克的和@马特加拉格尔的优良的答案,以及我的初始响应(参见此答案的一端)有一第三种方法,那就是使用宏/包括组合,可确保只键入变量名一次,因此,被包括在两个h和.M同时文件。

<强>

“总有另一种方式......”

在思考如何让它更简单,不涉及额外的头文件之后,这里是使用嵌套宏更简洁的方法。

<强>在h文件

#define defineKeysIn_h_File(key)   extern NSString * const key; 
#define defineKeysIn_m_File(key)   NSString * const key = @#key; 


#define myKeyDefineKeys(defineKey) \
/**start of key list*/\
defineKey(myKeyABC);\
defineKey(myKeyXYZ);\
defineKey(myKey123);\
/*end of key list*/

myKeyDefineKeys(defineKeysIn_h_File);

<强>在.m文件

myKeyDefineKeys(defineKeysIn_m_File);

<强>实施注意

您可以多次使用此更多个头,但你需要改变 “myKeyDefineKeys”的名称是独一无二的,我建议给它相同的前缀为您所定义的按键 - 为我用“的myKey”整个一个例子的缘故。

在另一文件I可能会使用 “myOtherKeyDefineKeys”。

同样做的defineKeysIn_h_File和defineKeysIn_m_File宏不乱,否则你会得到一个警告的定义已经改变了。

<强>

<强>原来的答案,仍然是有效的,但不仅精化

首先,做一个vanilla.h文件并删除默认的#ifdef等,并输入您的钥匙如下: (这是从类别剪切和粘贴我写延伸AVAudioPlayer)

//  playFromConsts.h


define_key(AVAudioPlayer_key_player);
define_key(AVAudioPlayer_key_duration);
define_key(AVAudioPlayer_key_filename);
define_key(AVAudioPlayer_key_filepath);
define_key(AVAudioPlayer_key_fileurl);
define_key(AVAudioPlayer_key_urlString);
define_key(AVAudioPlayer_key_envelope);
define_key(AVAudioPlayer_key_startDate);
define_key(AVAudioPlayer_key_linkToPlayer);
define_key(AVAudioPlayer_key_linkFromPlayer);
define_key(AVAudioPlayer_key_linkToPlayerEnvelope);
define_key(AVAudioPlayer_key_linkFromPlayerEnvelope);
define_key(AVAudioPlayer_key_deviceStartTime);
define_key(AVAudioPlayer_key_currentVolume);
define_key(AVAudioPlayer_key_fadeFromVolume);
define_key(AVAudioPlayer_key_fadeToVolume);
define_key(AVAudioPlayer_key_fadeTime);
define_key(AVAudioPlayer_key_segueTime);

然后在您normal.h文件(其中,你的@interface,@protocol等被声明)放置这些3行(代当然头文件)

#define define_key(x) extern NSString * const x; 
#include "playFromConsts.h"
#undef define_key

最后在.m文件,即配对与您 “@interface .H” 的文件,将这些3行:

#define define_key(x) NSString * const x = @#x; 
#include "playFromConsts.h"
#undef define_key

注意“的#include”而不是“#进口” - 我们其实要包含这个文件不止一次

这将尽一切肮脏的工作,并确保密钥的NSString * const的。

尾随;是可选的,因为它包含在宏,但是我个人更喜欢它。

因此毕竟。我想出了3个文件。

<强> Constants.h

#define def_key(name) extern NSString *const name
#define def_int(name, value) extern int const name
#define def_type(type, name, value) extern type const name

#include "ConstantsDefs.h"

<强> Constants.m

#import "Constants.h"

#undef def_key 
#define def_key(name) NSString *const name = @#name

#undef def_int
#define def_int(name, value) int const name = value

#undef def_type
#define def_type(type, name, value) type const name = value

#include "ConstantsDefs.h"

<强> ConstantsDefs.h

def_key(kStringConstant);
def_int(kIntConstant, 313373);
def_type(float, kFloatConstant, 313373.0f);

这要看你的软件的设计。假设你有一份工作管理软件和您的“违约”的一个是在各个项目可以保存的目录清单。

有关每个工作可以有一个storagefile构件,其在启动时加载了用户优选位置处的单例。

或者你可以有一个叫做用户首选项的全局变量的Storagefile成员。仍然可能是一个单身,但并不在这种情况下,真正的问题。

对于我来说复杂的默认值(几十种不同类型的类)应该驻留在自己的“空间”访问模型。

然而,有可能是对如何对作业设置,以便那些偏好需要被存储在工作对象重要的喜好,所以当你在另一个用户的应用程序中打开它,它按预期工作。

此外它取决于你的设计。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top