Константы в Objective-C
Я разрабатываю приложение Cocoa, и я использую константу NSString
как способы хранения имен ключей для своих настроек.
Я понимаю, что это хорошая идея, потому что это позволяет легко менять ключи, если это необходимо. Кроме того, это понятие "разделяет ваши данные с вашей логикой".
Во всяком случае, есть ли хороший способ сделать эти константы определенными один раз для всего приложения? Я уверен, что есть простой и разумный способ, но сейчас мои классы просто переопределяют те, которые они используют.
Ответы
Ответ 1
Вам следует создать файл заголовка, например
// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
//etc.
(вы можете использовать extern
вместо FOUNDATION_EXPORT
, если ваш код не будет использоваться в смешанных средах C/С++ или на других платформах)
Вы можете включить этот файл в каждый файл, который использует константы или в предварительно скомпилированном заголовке для проекта.
Вы определяете эти константы в файле .m, например
// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";
Константы .m должны быть добавлены в ваш целевой объект application/framework, чтобы он был связан с конечным продуктом.
Преимущество использования строковых констант вместо констант #define
'd заключается в том, что вы можете протестировать равенство, используя сравнение указателей (stringInstance == MyFirstConstant
), которое намного быстрее, чем сравнение строк ([stringInstance isEqualToString:MyFirstConstant]
) (и легче читать, ИМО).
Ответ 2
Самый простой способ:
// Prefs.h
#define PREFS_MY_CONSTANT @"prefs_my_constant"
Лучший способ:
// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;
// Prefs.m
NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";
Одно из преимуществ второго заключается в том, что изменение значения константы не приводит к перестройке всей вашей программы.
Ответ 3
Также есть одна вещь. Если вам нужна не глобальная константа, вы должны использовать ключевое слово static
.
Пример
// In your *.m file
static NSString * const kNSStringConst = @"const value";
Из-за ключевого слова static
эта константа не видна вне файла.
Небольшая коррекция @QuinnTaylor: статические переменные видны внутри единицы компиляции. Обычно это один файл .m(как в этом примере), но он может укусить вас, если вы объявите его в заголовке, который включен в другое место, поскольку после компиляции вы получите ошибки компоновщика
Ответ 4
В принятом (и правильном) ответе говорится, что "вы можете включить этот файл [Constants.h]... в предварительно скомпилированный заголовок для проекта".
Как новичок, мне было трудно это сделать без дальнейших объяснений - вот как: В вашем файле YourAppNameHere-Prefix.pch(это имя по умолчанию для предварительно скомпилированного заголовка в Xcode), импортируйте Constants.h внутри #ifdef __OBJC__
.
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "Constants.h"
#endif
Также обратите внимание, что файлы Constants.h и Constants.m должны содержать в себе абсолютно ничего, кроме того, что описано в принятом ответе. (Нет интерфейса или реализации).
Ответ 5
Я обычно использую способ, опубликованный Барри Wark и Rahul Gupta.
Хотя, я не люблю повторять одни и те же слова в файлах .h и .m.
Обратите внимание, что в следующем примере линия почти идентична в обоих файлах:
// file.h
extern NSString* const MyConst;
//file.m
NSString* const MyConst = @"Lorem ipsum";
Поэтому мне нравится использовать некоторые препроцессоры C.
Позвольте мне объяснить на примере.
У меня есть файл заголовка, который определяет макрос STR_CONST(name, value)
:
// StringConsts.h
#ifdef SYNTHESIZE_CONSTS
# define STR_CONST(name, value) NSString* const name = @ value
#else
# define STR_CONST(name, value) extern NSString* const name
#endif
В моей .h/.m-паре, где я хочу определить константу, я делаю следующее:
// myfile.h
#import <StringConsts.h>
STR_CONST(MyConst, "Lorem Ipsum");
STR_CONST(MyOtherConst, "Hello world");
// myfile.m
#define SYNTHESIZE_CONSTS
#import "myfile.h"
et voila, у меня есть вся информация о константах только в файле .h.
Ответ 6
Небольшая модификация предложения @Krizz, так что он работает правильно, если заголовочный файл констант должен быть включен в PCH, что довольно нормально. Поскольку оригинал импортируется в PCH, он не перезагружает его в файл .m
, и поэтому вы не получаете никаких символов, а компоновщик недоволен.
Однако следующая модификация позволяет ему работать. Это немного запутанно, но оно работает.
Вам понадобятся файлы 3, .h
, который содержит определения констант, файл .h
и файл .m
, я буду использовать ConstantList.h
, Constants.h
и Constants.m
, соответственно. содержимое Constants.h
просто:
// Constants.h
#define STR_CONST(name, value) extern NSString* const name
#include "ConstantList.h"
а файл Constants.m
выглядит следующим образом:
// Constants.m
#ifdef STR_CONST
#undef STR_CONST
#endif
#define STR_CONST(name, value) NSString* const name = @ value
#include "ConstantList.h"
Наконец, в файле ConstantList.h
есть фактические объявления в нем, и это все:
// ConstantList.h
STR_CONST(kMyConstant, "Value");
…
Несколько замечаний:
-
Мне пришлось переопределить макрос в файле .m
после #undef
для его использования.
-
Мне также пришлось использовать #include
вместо #import
, чтобы это работало правильно и не позволяло компилятору видеть ранее предварительно скомпилированные значения.
-
Это потребует перекомпиляции вашего PCH (и, возможно, всего проекта), когда будут изменены какие-либо значения, что не так, если они разделены (и дублируются) как обычно.
Надеюсь, что это поможет кому-то.
Ответ 7
У меня есть заголовок, посвященный объявлению постоянных NSStrings, используемых для таких настроек:
extern NSString * const PPRememberMusicList;
extern NSString * const PPLoadMusicAtListLoad;
extern NSString * const PPAfterPlayingMusic;
extern NSString * const PPGotoStartupAfterPlaying;
Затем объявляем их в сопроводительном файле .m:
NSString * const PPRememberMusicList = @"Remember Music List";
NSString * const PPLoadMusicAtListLoad = @"Load music when loading list";
NSString * const PPAfterPlayingMusic = @"After playing music";
NSString * const PPGotoStartupAfterPlaying = @"Go to startup pos. after playing";
Этот подход хорошо послужил мне.
Изменить: обратите внимание, что это лучше всего работает, если строки используются в нескольких файлах. Если используется только один файл, вы можете просто сделать #define kNSStringConstant @"Constant NSString"
в файле .m, который использует строку.
Ответ 8
// Prefs.h
extern NSString * const RAHUL;
// Prefs.m
NSString * const RAHUL = @"rahul";
Ответ 9
Как сказал Abizer, вы можете поместить его в файл PCH. Другой способ, который не настолько грязный, состоит в том, чтобы сделать файл include для всех ваших ключей, а затем либо включить его в файл, в котором вы используете ключи, либо включить его в PCH. С их помощью в свой собственный файл include это по крайней мере дает вам одно место для поиска и определения всех этих констант.
Ответ 10
Если вы хотите что-то вроде глобальных констант; быстрый грязный способ состоит в том, чтобы поместить объявления констант в файл pch
.
Ответ 11
Попробуйте использовать метод класса:
+(NSString*)theMainTitle
{
return @"Hello World";
}
Я использую его иногда.
Ответ 12
Я использую одноэлементный класс, чтобы я мог издеваться над классом и изменять константы, если это необходимо для тестирования. Класс констант выглядит следующим образом:
#import <Foundation/Foundation.h>
@interface iCode_Framework : NSObject
@property (readonly, nonatomic) unsigned int iBufCapacity;
@property (readonly, nonatomic) unsigned int iPort;
@property (readonly, nonatomic) NSString * urlStr;
@end
#import "iCode_Framework.h"
static iCode_Framework * instance;
@implementation iCode_Framework
@dynamic iBufCapacity;
@dynamic iPort;
@dynamic urlStr;
- (unsigned int)iBufCapacity
{
return 1024u;
};
- (unsigned int)iPort
{
return 1978u;
};
- (NSString *)urlStr
{
return @"localhost";
};
+ (void)initialize
{
if (!instance) {
instance = [[super allocWithZone:NULL] init];
}
}
+ (id)allocWithZone:(NSZone * const)notUsed
{
return instance;
}
@end
И он используется как это (обратите внимание на использование сокращения для констант c - он сохраняет типизацию [[Constants alloc] init]
каждый раз):
#import "iCode_FrameworkTests.h"
#import "iCode_Framework.h"
static iCode_Framework * c; // Shorthand
@implementation iCode_FrameworkTests
+ (void)initialize
{
c = [[iCode_Framework alloc] init]; // Used like normal class; easy to mock!
}
- (void)testSingleton
{
STAssertNotNil(c, nil);
STAssertEqualObjects(c, [iCode_Framework alloc], nil);
STAssertEquals(c.iBufCapacity, 1024u, nil);
}
@end
Ответ 13
Если вам нравится константа пространства имен, вы можете использовать struct, Friday Q & A 2011-08-19: Константы и функции имен, основанные на именах
// in the header
extern const struct MANotifyingArrayNotificationsStruct
{
NSString *didAddObject;
NSString *didChangeObject;
NSString *didRemoveObject;
} MANotifyingArrayNotifications;
// in the implementation
const struct MANotifyingArrayNotificationsStruct MANotifyingArrayNotifications = {
.didAddObject = @"didAddObject",
.didChangeObject = @"didChangeObject",
.didRemoveObject = @"didRemoveObject"
};
Ответ 14
Если вы хотите вызвать что-то вроде этого NSString.newLine;
из цели c, и вы хотите, чтобы она была статической константой, вы можете создать что-то вроде этого в swift:
public extension NSString {
@objc public static let newLine = "\n"
}
И у вас есть хорошее читаемое определение константы, которое доступно из любого типа по вашему выбору, в то время как стиль ограничен контекстом типа.
Ответ 15
Пожалуйста, проверьте эту ссылку для демонстрации констант в Objective C. Просто Загружайте файлы и импортируйте их в Project и используйте.
https://github.com/mspviraj/constants-in-Objective-C
Пример кода:
/* App Color Codes */
#define KAppBackgroundColor 0x202020
#define KSecondaryBackgroundColor 0x333333
#define KAppFontColor 0xffffff
#define KAppFontColorAlpha 0