在iOS应用中,最好的常量存储位置是哪里?

37

我正在开发一个应用程序,它从JSON API获取资源。

所有的资源都有相同的基础URL:

http://api.mysite.com/resources.json
http://api.mysite.com/other_resources.json

我希望将字符串http://api.mysite.com/存储,以便所有的控制器和模型都可以使用它,在编写资源URL时减少一些重复。最佳存储位置在哪里?是-prefix.pch文件吗?任何建议将不胜感激。
5个回答

65

我同意Alex Coplan的答案,并有一个重要的补充。

把所有常量放在一个名为"Constants.h"(或其他你想要的名称)的文件中。

编辑:

  • 三年前回答这个问题时,我是支持使用#define的,查看下面的修订记录。

Constants.h

#define kFilterDate @"date"
#define kFilterRadius @"radius"
#define kFilterSort @"sort"

//Global Strings
#define kDividingString @" / "

//Strings
#define kTour @"Tour"
#define kToursKey @"tours"

但是,不要在任何需要它的文件中导入它,而是在你的前缀文件中导入它,这样你的项目中所有的头文件都会自动导入它。

Project_Prefix.pch

//
// Prefix header for all source files of the project
//

#ifdef __OBJC__
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    #import "Constants.h"
#endif

修订

虽然所有先前的信息仍然有效,但是我们可以采取一些措施,使我们的常量更加安全。

使用const变量在您的Constants.h文件中创建您的常量。

//Filters
FOUNDATION_EXPORT NSString *const kFilterDate;
FOUNDATION_EXPORT NSString *const kFilterRadius;
FOUNDATION_EXPORT NSString *const kFilterSort;

//Global Strings
FOUNDATION_EXPORT NSString *const kDividingString;

//Strings
FOUNDATION_EXPORT NSString *const kTour;
FOUNDATION_EXPORT NSString *const kToursKey;

Constants.m文件中

//Filters
NSString *const kFilterDate = @"date";
NSString *const kFilterRadius = @"radius";
NSString *const kFilterSort = @"sort";

//Global Strings
NSString *const kDividingString = @" / ";

//Strings
NSString *const kTour = @"Tour";
NSString *const kToursKey = @"tours";

仍然可以像上面那样导入到您的前缀文件中,但只使用在文件中真正全局使用的常量。将所有常量都倾泻到此文件中将导致使用任何常量的代码与常量文件耦合。因此,如果您尝试重用代码,则必须同时使用常量文件。这并不总是一件坏事,并且许多时候是有意为之(这很好),但限制依赖关系总是一个好主意。

修订版本的一些细节:

  • FOUNDATION_EXPORTextern。前者在 C 和 C++ 中编译不同。它基本上意味着 extern,但在 C++ 中会添加“C”标志。
  • constsdefinesconsts 是类型安全的并且尊重作用域,而 defines 则完全相反。

我讨厌使用.h .m来定义全局常量。每次都要写两遍变量名真是太痛苦了! - Hlung
3
拥有干净、一致、易读的代码价值是你付出两倍努力所得到的十倍。 - ColdLogic
对于以下情况,我该怎么办?我遇到了错误“initialize element is not compile time constant for USER_LIST_URL”。<code> NSString *const SERVER_URL = @"http://www.google.com"; NSString *const USER_LIST_URL = [NSString stringWithFormat:@"%@/xml/index.cfm",SERVER_URL];</code> - Abbas Mulani

48

就我个人而言,我更喜欢使用实际的常量变量而不是宏定义。

在一个名为MyConstants.m的文件中,我有以下内容:

NSString *const kXYMySiteBaseURL = @"http://api.mysite.com/";
NSString *const kXYSomeOtherURL = @"http://www.google.com/";

其中XY是我的缩写或者其他“唯一”前缀,以避免与其他常量发生冲突。

然后我有一个像这样的MyConstants.h文件:

extern NSString *const kXYMySitBaseURL;
extern NSString *const kXYSomeOtherURL;

根据需要访问这些常量的文件数量的不同,我可能会像ColdFusion在他的回答中建议的那样将其包含在预编译头文件中。

这就是大多数核心框架中苹果公司定义其常量的方式。


2
我知道这可能是微不足道的差异 - 但是在内存方面,定义一次常量(在应用程序生命周期内存在)与使用宏定义实例/局部变量并在运行时进行垃圾回收有什么影响? - bodacious
正如您在此处阅读的:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html,苹果鼓励您不要使用#define宏。这就是为什么我更喜欢这个答案而不是之前的答案。 - voghDev
这是一些内存节省。另外的好处是像 isEqual: 或 isEqualToString 这样的东西不会因为它们是相同的指针而费时比较字符串。 - gnasher729

12

我刚刚创建了一个名为Globals.h的文件,并添加了以下内容:

#define kBaseURL @"http://api.mysite.com/"

然后使用:

#import "Globals.h" // at the top

NSString *url = [NSString stringWithFormat:@"%@resources.json",kBaseURL];

我认为这是最好的方法。 - The dude

4
我会创建一个单例或使用AppDelegate,并将常量放在那里。

在创建单例之前,我会非常非常仔细地考虑 - 它们会使单元测试变得非常困难,并且通常可以在没有单例的情况下实现相同的功能。使用应用程序委托是更好的解决方案,但仍然不理想。许多人认为在应用程序委托上承担过多责任是不良设计。我个人会选择创建一个全局头文件,其中仅包含常量,如Alex Coplan的答案所述。 - Will Pragnell
@WillPragnell 头文件如何比单例更容易进行单元测试?通常情况下,单例会使单元测试变得困难,但这似乎正是单例发挥作用的地方。 - Jackson

4

是的,全局头部将是一个理想的解决方案。除非您计划将其用于其他事情,如管理数据存储,否则我不会选择单例模式。对于全局变量而言,使用单例有些过度。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接