static const Vs extern const

我一直在我的头文件中使用静态常量,如下所示:

static NSString * const myString = @"foo"; 

但是已经读过,这不是“安全”或正确的做法。 显然,如果我想要从另一个类访问我的conststring,我应该在我的.h中声明string:

 extern NSString * const myString; 

然后在我的.m文件中:

 NSString * const myString = @"foo"; 

它是否正确? 如果是这样,什么原因不直接在我的.h文件中声明它是静态的? 它工作得很好,我也看不到任何“安全”问题。 这是一个常量,因此它不能从外部改变,而且它是我有意在类之外访问的东西。 我能想到的唯一的另一件事是隐藏string的价值?

你的第一个变种

 static NSString * const myString = @"foo"; // In .h file, included by multiple .m files 

在包含头文件的每个“翻译单元” (粗略地说,在每个.m源文件中)中本地定义一个myStringvariables。 所有string对象都具有相同的内容“foo”,但它可能是不同的对象,所以myString指向string对象的指针 )的值可能在每个单元中是不同的。

你的第二个变种

 extern NSString * const myString; // In .h file, included by multiple .m files NSString * const myString = @"foo"; // In one .m file only 

定义了一个 “全局”可见的variablesmyString

例如:在一个类中,您发送一个myString作为用户对象的通知。 在另一个类中,这个通知被接收,用户对象与myString进行比较。

在你的第一个变体中, 必须isEqualToString: 来完成比较isEqualToString:因为发送和接收类可能有不同的指针(都指向一个内容为“foo”的NSString对象)。 因此与==比较可能会失败。

在你的第二个变种中,只有一个myStringvariables,所以你可以用==比较。

所以第二个变体是更安全的,因为“共享string”是每个翻译单元中的同一个对象

我不知道在Objective-C中声明任何外部的东西,而只在你的项目中使用Objective-C。 当你将它与C或汇编模块混合时,我可以想到原因

然而, extern的优点是,如果你真的需要保存这20个左右的字节,那么这个常量在整个项目中才真正存在。 但是这会带来相互冲突的风险。 其他图书馆可能已经使用相同的名称宣布他们自己的外部。 链接器会使用内存中相同的空间来关心它们,虽然它们可能是不同的types。

是的,头文件中的extern声明应该伴随.m文件中的相应定义。 我不知道,但我认为你可以在.h文件中分配@“foo”。 你甚至可以在@interface / @ implementation- @ end块之外声明它。 (从来没有尝试过我自己)。 在这种情况下,variables将是全局的,即使没有extern关键字,也可以从任何地方访问。 在编译时,编译器会抱怨在#include语句链中没有看到它的声明时访问它们。 但在学术上,一个单一的.m文件可能包含两个或更多的类(我明显不build议),然后variables将可以从两个类访问,虽然它不属于他们。 最后,OjbC只是ANSI C的一个附件。

但是,把它们变成静态是没有意义的。 无论如何,这些常量是静态的。 他们是常数。 一个类或甚至方法中的静态variables的目的是它的范围(可见性)仅限于该类,但运行时只有一个实例被该类的所有实例共享。

例:

 @implementation AClass : NSObject static NSString *someString - (void) setString:(NSString*) aString{ someString = aString; } - (NSString*) getString (){ return someString; } 

…和其他地方:

 AClass * a = [[AClass alloc] init]; AClass * b = [[AClass alloc] init]; [a setString:@"Me"]; [b setString;@"You"]; NSLog (@"String of a: ", [a getString]); 

会打印出You而不是Me

如果这是你想要的,只有这样,使用静态。

使用简单的预处理macros(我喜欢,但我在这里有点老)有缺点,这些string将被复制到二进制文件,每当使用macros。 显然这不是你的select,因为你甚至没有要求他们。 但是,对于大多数用法来说,共享的.h文件中的预处理器macros将会处理跨类的常量pipe理。

使用static NSString* const myString = @"foo"; 在头文件中意味着每个翻译单元都得到一个单独的myStringvariables。 我认为链接器可以巩固这些,但我不会指望它。 这意味着,如果调用者来自不同的翻译单元,那么即使调用者传递了myString ,也会使用if (someString == myString) ...来比较它所接收到的string。 (当然,代码应该使用-isEqualToString:而不是== ,但是使用正确声明的string常量,后者可能是可行的。)

其他答案描述了外部方式的优点。

如果variables不是一个对象(在你的情况下是NSString )而是一个基本types(如整数),静态方式的一个可能的好处是,编译器能够优化对常量的访问:

当你在程序中声明一个const时,

 int const x = 2; 

编译器可以通过不为这个variables提供存储而是将其添加到符号表中来优化这个常量。 所以,后续的读取只需要间接进入符号表而不是从内存中获取值的指令。

从这个答案采取。

但是已经读过,这不是“安全”或正确的做这件事的警惕。

这是安全的,除非程序是multithreading的。 在这种情况下,除非用互斥锁保护全局variables,否则不安全。

然而,这是不正确的。 NSString * const myString表示一个指向(非常量)数据的常量指针。 最有可能的是,你希望variables本身是常量: const NSString* myString

显然,如果我想我的conststring从另一个类访问我应该声明在我的.hstring为: extern

正确。 请注意, extern只能用于常量。 对于非常量variables是不可接受的:全局variables被认为是非常糟糕的做法。

如果是这样的话,不要直接在我的.h文件中声明它是静态的,因为它工作的很好

为什么要把它声明为静态的唯一原因是因为你想限制variables的范围到本地的.c文件,换句话说就是私有封装 。 因此,在.h文件中声明静态variables是没有任何意义的。

这是一个常量因此不能从外部改变

它可以改变,因为它不是常量,看到我的第一个评论。


一般来说,不要这样做。 以上所有的摆弄都表明,你的程序devise有缺陷,需要修正。 您需要以面向对象的方式devise您的程序,以便每个代码模块都是自治的,除了指定的任务外,不知道或关心任何事情。

说到存储类,静态意味着两件事情之一。

方法或函数内的静态variables在调用之间保留其值。

全局声明的静态variables可以被任何函数或方法调用,只要这些函数与静态variables出现在相同的文件中。 静态function也是如此。

而静态使得函数和variables在特定文件中是全局可见的,而extern使得它们对所有文件全局可见。

任何时候,当应用程序在公共接口中使用一个非语言值的string常量时,应该将其声明为一个外部string常量。

该模式是在公共头文件中声明一个外部NSString * const,并在实现中定义NSString * const。

资料来源: nshipster.com/c-storage-classes

 #define myString @"foo" 

有例子为什么:

您将能够在编译时连接string:

 NSLog(@"%@", @"Say hello to " myString); 

将输出:向foo致意