iOS 应用程序中全局常量存储在哪里?

发布于 2024-11-30 20:37:57 字数 860 浏览 1 评论 0 原文

我的 iOS 应用程序中的大多数模型都会查询 Web 服务器。我想要一个存储服务器基本 URL 的配置文件。它看起来像这样:

// production
// static NSString* const baseUrl = "http://website.example/"

// testing
static NSString* const baseUrl = "http://192.168.0.123/"

通过注释掉一行或另一行,我可以立即更改我的模型指向的服务器。我的问题是,在 iOS 中存储全局常量的最佳实践是什么?在Android编程中,我们有这个内置的字符串资源文件。在任何 Activity 中(相当于 UIViewController),我们可以通过以下方式检索这些字符串常量:

String string = this.getString(R.string.someConstant);

我想知道 iOS SDK 是否有类似的存储位置常数。如果没有,Objective-C 中这样做的最佳实践是什么?

Most of the models in my iOS app query a web server. I would like to have a configuration file storing the base URL of the server. It will look something like this:

// production
// static NSString* const baseUrl = "http://website.example/"

// testing
static NSString* const baseUrl = "http://192.168.0.123/"

By commenting out one line or the other, I can instantly change which server my models point to. My question is, what's the best practice for storing global constants in iOS? In Android programming, we have this built-in strings resource file. In any Activity (the equivalent of a UIViewController), we can retrieve those string constants with:

String string = this.getString(R.string.someConstant);

I was wondering if the iOS SDK has an analogous place to store constants. If not, what is the best practice in Objective-C to do so?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

蓝天 2024-12-07 20:37:58

好吧,您希望声明位于与其相关的接口的本地——应用程序范围的常量文件不是一件好事。

同样,最好简单地声明一个 extern NSString* const 符号,而不是使用 #define


SomeFile.h

extern NSString* const MONAppsBaseUrl;

SomeFile .m

#import "SomeFile.h"

#ifdef DEBUG
NSString* const MONAppsBaseUrl = @"http://192.168.0.123/";
#else
NSString* const MONAppsBaseUrl = @"http://website.example/";
#endif

除了省略了 C++ 兼容的 Extern 声明之外,这是您通常会在 Apple 的 Obj-C 框架中看到的使用方式。

如果该常量只需要对一个文件或函数可见,那么 *.m 中的 static NSString* const baseUrl 是不错的选择。

Well, you want the declaration local to the interfaces it relates to -- the app-wide constants file is not a good thing.

As well, it's preferable to simply declare an extern NSString* const symbol, rather than use a #define:


SomeFile.h

extern NSString* const MONAppsBaseUrl;

SomeFile.m

#import "SomeFile.h"

#ifdef DEBUG
NSString* const MONAppsBaseUrl = @"http://192.168.0.123/";
#else
NSString* const MONAppsBaseUrl = @"http://website.example/";
#endif

Apart from the omission of the C++ compatible Extern declaration, this is what you will generally see used in Apple's Obj-C frameworks.

If the constant needs to be visible to just one file or function, then static NSString* const baseUrl in your *.m is good.

不顾 2024-12-07 20:37:58

您还可以

#define kBaseURL @"http://192.168.0.123/"

在“常量”头文件中执行 a,例如 constants.h。然后

#include "constants.h"

在需要此常量的每个文件的顶部执行此操作。

这样,您可以根据编译器标志在服务器之间切换,如下所示:

#ifdef DEBUG
    #define kBaseURL @"http://192.168.0.123/"
#else
    #define kBaseURL @"http://myproductionserver.example/"
#endif

You could also do a

#define kBaseURL @"http://192.168.0.123/"

in a "constants" header file, say constants.h. Then do

#include "constants.h"

at the top of every file where you need this constant.

This way, you can switch between servers depending on compiler flags, as in:

#ifdef DEBUG
    #define kBaseURL @"http://192.168.0.123/"
#else
    #define kBaseURL @"http://myproductionserver.example/"
#endif
吹梦到西洲 2024-12-07 20:37:58

我定义全局常量的方式:


AppConstants.h

extern NSString* const kAppBaseURL;

AppConstants.m

#import "AppConstants.h"

#ifdef DEBUG
NSString* const kAppBaseURL = @"http://192.168.0.123/";
#else
NSString* const kAppBaseURL = @"http://website.example/";
#endif

然后在您的 {$APP}-Prefix.pch 文件中:

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

如果您遇到任何问题,请首先确保您已将“预编译前缀标头”选项设置为“否”。

The way I define global constants:


AppConstants.h

extern NSString* const kAppBaseURL;

AppConstants.m

#import "AppConstants.h"

#ifdef DEBUG
NSString* const kAppBaseURL = @"http://192.168.0.123/";
#else
NSString* const kAppBaseURL = @"http://website.example/";
#endif

Then in your {$APP}-Prefix.pch file:

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

If you experience any problems, first make sure that you have the Precompile Prefix Header option set to NO.

自由范儿 2024-12-07 20:37:58

您还可以像这样连接字符串常量:

  #define kBaseURL @"http://myServer.example"
  #define kFullURL kBaseURL @"/api/request"

You can also concatenate string constants like this:

  #define kBaseURL @"http://myServer.example"
  #define kFullURL kBaseURL @"/api/request"
入怼 2024-12-07 20:37:58

我确实认为另一种方法要简单得多,您只需将其包含在需要包含它们的文件中,而不是所有文件中,就像使用 .pch 前缀文件一样:

#ifndef Constants_h
#define Constants_h

//Some constants
static int const ZERO = 0;
static int const ONE = 1;
static int const TWO = 2;

#endif /* Constants_h */

之后,您可以将此头文件包含在头文件中你想要的。您可以将其包含在您希望将其包含在其中的特定类的头文件中:

#include "Constants.h"

I do think that another way to do this is far simpler and you will just include it in files you need them included in, not ALL the files, like with the .pch prefix file:

#ifndef Constants_h
#define Constants_h

//Some constants
static int const ZERO = 0;
static int const ONE = 1;
static int const TWO = 2;

#endif /* Constants_h */

After that you include this header file in the header file that you want. You include it in header file for the specific class that you want it included in:

#include "Constants.h"
最笨的告白 2024-12-07 20:37:58
  1. 我在 YOURPROJECT-Prefix.pch 文件中定义全局常量。
  2. #define BASEURl @"http://myWebService.appspot.com/xyz/xx"
  3. 然后在项目中的任何位置使用 BASEURL:

    NSString *LOGIN_URL= [BASEURl stringByAppendingString:@"/users/login"];
    

更新:
在 Xcode 6 中,您将找不到在项目中创建的默认 .pch 文件。因此,请使用 Xcode 6 中的 PCH 文件 在项目中插入 .pch 文件。

更新:
对于 SWIFT

  1. 创建新的 Swift 文件 [空无类] 说 [AppGlobalMemebers]
  2. &立即声明/定义成员

    示例:

    var STATUS_BAR_GREEN : UIColor = UIColor(红色: 106/255.0, 绿色: 161/255.0, 蓝色: 7/255.0, alpha: 1) //
    
  3. 如果您想在任何类文件(例如 Appdelegate 或 Singleton 类或任何类)中定义应用程序全局成员,请在类定义上方声明给定成员
  1. I define global constant in YOURPROJECT-Prefix.pch file.
  2. #define BASEURl @"http://myWebService.appspot.com/xyz/xx"
  3. then anywhere in project to use BASEURL:

    NSString *LOGIN_URL= [BASEURl stringByAppendingString:@"/users/login"];
    

Updated:
In Xcode 6 you will not find default .pch file created in your project. So please use PCH File in Xcode 6 to insert .pch file in your project.

Updates:
For SWIFT

  1. Create new Swift file [empty without class] say [AppGlobalMemebers]
  2. & Right away declare / define member

    Example:

    var STATUS_BAR_GREEN : UIColor  = UIColor(red: 106/255.0, green: 161/255.0, blue: 7/255.0, alpha: 1)  //
    
    1. If you want to define the app global member in any class file say Appdelegate or Singleton class or any, declare given member above class definition
圈圈圆圆圈圈 2024-12-07 20:37:58

全局声明很有趣,但对我来说,深刻改变我的编码方式的是拥有类的全局实例。我花了几天时间才真正理解如何使用它,所以我在这里快速总结了它,

我使用类的全局实例(每个项目 1 或 2 个,如果需要),来重新组合核心数据访问或一些交易逻辑。

例如,如果您希望有一个中央对象来处理所有餐厅餐桌,您可以在启动时创建对象,仅此而已。该对象可以处理数据库访问,或者如果不需要保存它,也可以在内存中处理它。它是集中式的,您只显示有用的界面......!

这是一个很大的帮助,面向对象,并且是一种将所有东西放在同一个地方的好方法

几行代码:

@interface RestaurantManager : NSObject
    +(id) sharedInstance;
    -(void)registerForTable:(NSNumber *)tableId;
@end 

和对象实现:

@implementation RestaurantManager

+ (id) sharedInstance {
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        sharedInstance = [[self alloc] init];
        NSLog(@"*** Shared instance initialisation ***");
    });
    return sharedInstance;
}

-(void)registerForTable:(NSNumber *)tableId {
}
@end

使用它非常简单:

[[RestaurantManager共享实例]registerForTable:[NsNumber
numberWithInt:10]]

Global declarations are interesting but, for me, what changed deeply my way to code was to have global instances of classes. It took me a couple of day's to really understand how to work with it so I quickly summarized it here

I use global instances of classes (1 or 2 per project, if needed), to regroup core data access, or some trades logics.

For instance if you want to have a central object handling all restaurant tables you create you object at startup and that is it. This object can handle database accesses OR handle it in memory if you don't need to save it. It's centralized, you show only useful interfaces ... !

It's a great help, object oriented and a good way to get all you stuff at the same place

A few lines of code :

@interface RestaurantManager : NSObject
    +(id) sharedInstance;
    -(void)registerForTable:(NSNumber *)tableId;
@end 

and object implementation :

@implementation RestaurantManager

+ (id) sharedInstance {
    static dispatch_once_t onceQueue;

    dispatch_once(&onceQueue, ^{
        sharedInstance = [[self alloc] init];
        NSLog(@"*** Shared instance initialisation ***");
    });
    return sharedInstance;
}

-(void)registerForTable:(NSNumber *)tableId {
}
@end

for using it it's really simple :

[[RestaurantManager sharedInstance] registerForTable:[NsNumber
numberWithInt:10]]

成熟稳重的好男人 2024-12-07 20:37:58

接受的答案有两个缺点。
首先,正如其他人指出的那样,使用 #define 更难调试,请使用 extern NSString* const kBaseUrl 结构。
其次,它为常量定义了一个文件。 IMO,这是错误的,因为大多数类不需要访问这些常量或访问所有这些常量,而且如果所有常量都在那里声明,文件可能会变得臃肿。更好的解决方案是在 3 个不同层对常量进行模块化:

  1. 系统层:SystemConstants.hAppConstants.h,它们描述全局范围内的常量,可以是可以被系统中的任何类访问。此处仅声明那些必须从不相关的不同类访问的常量。

  2. 模块/子系统层:ModuleNameConstants.h,描述一组常量,这些常量对于模块/子系统内部的一组相关类来说是典型的。

  3. 类层:常量驻留在类中,仅由类使用。

只有 1,2 与问题相关。

The accepted answer has 2 weaknesses.
First, as others pointed is usage of #define which is harder to debug, use instead extern NSString* const kBaseUrl structure.
Second, it defines a single file for constants. IMO, this is wrong because most of classes don't need access to those constants or to access all of them plus file can become bloated if all constants are declared there. A better solution would be to modularize constants at 3 different layers:

  1. System layer: SystemConstants.h or AppConstants.h which describes constants at global scope, which can be accessed by any class in the system. Declare here only those constants that must be accessed from different classes that are not related.

  2. Module/Sub-system layer: ModuleNameConstants.h, describes a set of constants which are typical for a set of related classes, inside of a module/sub-system.

  3. Class layer: Constants resides in the class and are used only by it.

Only 1,2 are related to the question.

不语却知心 2024-12-07 20:37:58

我之前使用过的方法是创建一个文件 Settings.plist 并在启动时使用 registerDefaults: 将其加载到 NSUserDefaults 中。然后,您可以通过以下方式访问其内容:

// Assuming you've defined some constant kMySettingKey.
[[NSUserDefaults standardUserDefaults] objectForKey:kMySettingKey];

虽然我没有进行任何 Android 开发,但听起来这类似于您描述的字符串资源文件。唯一的缺点是您无法使用预处理器在设置之间进行交换(例如在DEBUG 模式下)。不过,我想你可以加载不同的文件。

NSUserDefaults 文档。

An approach I've used before is to create a file Settings.plist and load it into NSUserDefaults upon launch using registerDefaults:. You can then access its contents with the following:

// Assuming you've defined some constant kMySettingKey.
[[NSUserDefaults standardUserDefaults] objectForKey:kMySettingKey];

While I haven't done any Android development, it sounds as though this is analogous to the strings resource file you described. The only downside is that you can't use the preprocessor to swap between settings (e.g. in DEBUG mode). I suppose you could load in a different file, though.

NSUserDefaults documentation.

半枫 2024-12-07 20:37:58

对于一个数字,你可以像这样使用它

#define MAX_HEIGHT 12.5

For a number you can use it like

#define MAX_HEIGHT 12.5
皇甫轩 2024-12-07 20:37:58

我会使用从plist初始化的配置对象
为什么要用不相关的外部东西来打扰其他类呢?

为此,我单独创建了 eppz!settigns 。请参阅文章保存到 NSUserDefaults 的高级而简单的方法,以合并来自 的默认值plist

在此处输入图像描述

I'd use a configuration object that initializes from a plist.
Why bother other classes with irrelevant external stuff?

I created eppz!settigns soley for this reason. See article Advanced yet simple way to save to NSUserDefaults for incorporating default values from a plist.

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文