我的iOS应用中的大多数模型都在查询网络服务器。我想有一个配置文件存储服务器的基本URL。它看起来像这样:
// production
// static NSString* const baseUrl = "http://website.com/"
// testing
static NSString* const baseUrl = "http://192.168.0.123/"
通过注释掉一行或另一行,我可以立即更改模型指向的服务器。我的问题是,在iOS中存储全局常量的最佳实践是什么?在Android编程中,我们有这个内置的strings resource file。在任何Activity(相当于UIViewController)中,我们可以通过以下方式检索这些字符串常量:
String string = this.getString(R.string.someConstant);
我想知道iOS SDK是否具有存储常量的类似位置。如果没有,Objective-C中的最佳做法是什么?
答案 0 :(得分:167)
嗯,你想要与它相关的接口本地声明 - 应用程序范围的常量文件不是一件好事。
同样,最好只声明一个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.com/";
#endif
除了省略C ++兼容的Extern声明之外,这是您在Apple的Obj-C框架中通常会看到的。
如果常量只需要对一个文件或函数可见,那么static NSString* const baseUrl
中的*.m
就可以了。
答案 1 :(得分:145)
你也可以做一个
#define kBaseURL @"http://192.168.0.123/"
在“常量”头文件中,例如constants.h
。然后做
#include "constants.h"
位于您需要此常量的每个文件的顶部。
这样,您可以根据编译器标志在服务器之间切换,如:
#ifdef DEBUG
#define kBaseURL @"http://192.168.0.123/"
#else
#define kBaseURL @"http://myproductionserver.com/"
#endif
答案 2 :(得分:39)
我定义全局常量的方式:
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.com/";
#endif
然后在你的{$ APP} -Prefix.pch文件中:
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "AppConstants.h"
#endif
如果遇到任何问题,请首先确保将Precompile Prefix Header选项设置为NO。
答案 3 :(得分:5)
您还可以像这样连接字符串常量:
#define kBaseURL @"http://myServer.com"
#define kFullURL kBaseURL @"/api/request"
答案 4 :(得分:3)
#define BASEURl @"http://myWebService.appspot.com/xyz/xx"
然后项目中的任何地方使用BASEURL:
NSString *LOGIN_URL= [BASEURl stringByAppendingString:@"/users/login"];
更新: 在Xcode 6中,您将找不到项目中创建的默认.pch文件。因此,请使用PCH File in Xcode 6在项目中插入.pch文件。
更新: 对于SWIFT
&安培;马上声明/定义成员
示例:
var STATUS_BAR_GREEN : UIColor = UIColor(red: 106/255.0, green: 161/255.0, blue: 7/255.0, alpha: 1) //
答案 5 :(得分:3)
我认为另一种方法更简单,你只需将它包含在你需要它们的文件中,而不是所有文件中,例如.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"
答案 6 :(得分:2)
全局声明很有意思,但对我来说,改变代码的方式是拥有类的全局实例。我花了几天时间才真正了解如何使用它,所以我在这里快速总结了它
我使用全局类实例(每个项目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 sharedInstance] registerForTable:[NsNumber numberWithInt:10]
答案 7 :(得分:0)
我之前使用过的方法是创建文件Settings.plist
并在使用NSUserDefaults
启动时将其加载到registerDefaults:
。然后,您可以使用以下内容访问其内容:
// Assuming you've defined some constant kMySettingKey.
[[NSUserDefaults standardUserDefaults] objectForKey:kMySettingKey];
虽然我没有进行任何Android开发,但听起来好像这与您描述的字符串资源文件类似。唯一的缺点是您无法使用预处理器在设置之间进行切换(例如,在DEBUG
模式下)。我想你可以加载一个不同的文件。
答案 8 :(得分:0)
对于一个号码,您可以像
一样使用它#define MAX_HEIGHT 12.5
答案 9 :(得分:0)
接受的答案有两个缺点。
首先,正如其他人所指出的那样,#define
的使用更难以调试,而是使用extern NSString* const kBaseUrl
结构。
其次,它为常量定义了一个文件。 IMO,这是错误的,因为大多数类都不需要访问这些常量或访问所有这些常量,如果在那里声明所有常量,文件会变得臃肿。更好的解决方案是在3个不同的层上模块化常数:
系统层:SystemConstants.h
或AppConstants.h
,描述全局范围内的常量,可由系统中的任何类访问。这里只声明那些必须从不相关的不同类访问的常量。
模块/子系统层:ModuleNameConstants.h
,描述一组常量,这些常量对于模块/子系统内的一组相关类是典型的。
类层:常量驻留在类中,仅由它使用。
只有1,2与问题有关。
答案 10 :(得分:-1)
我使用从plist
初始化的配置对象。
为什么要用其他不相关的外部东西来打扰其他类?
出于这个原因,我创建了eppz!settigns
soley。有关合并plist
的默认值,请参阅文章Advanced yet simple way to save to NSUserDefaults。