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源文件中)中本地定义一个myString
variables。 所有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
对象)。 因此与==
比较可能会失败。
在你的第二个变种中,只有一个myString
variables,所以你可以用==
比较。
所以第二个变体是更安全的,因为“共享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";
在头文件中意味着每个翻译单元都得到一个单独的myString
variables。 我认为链接器可以巩固这些,但我不会指望它。 这意味着,如果调用者来自不同的翻译单元,那么即使调用者传递了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致意