Stałe w Objective-C

Rozwijam aplikację Cocoa i używam stałych NSString s jako sposobów przechowywania nazw kluczy dla moich preferencji.

Rozumiem, że to dobry pomysł, ponieważ pozwala na łatwą zmianę kluczy, jeśli to konieczne. Plus, to całe "oddziel swoje dane od logiki" pojęcie.

W każdym razie, czy jest dobry sposób, aby te stałe zdefiniowane raz dla całej aplikacji? Jestem pewien, że jest łatwy i inteligentny sposób, ale teraz moje zajęcia po prostu redefiniują te używają.

Author: Peter Mortensen, 2009-02-12

13 answers

Powinieneś utworzyć plik nagłówka jak

// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
//etc.

(możesz użyć extern zamiast FOUNDATION_EXPORT, Jeśli Twój kod nie będzie używany w mieszanych środowiskach C / C++ lub na innych platformach)

Możesz dołączyć ten plik do każdego pliku, który używa stałych lub do wstępnie skompilowanego nagłówka dla projektu.

Definiujesz te stałe wm plik jak

// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";

Stałe.m powinien być dodany do celu Twojej aplikacji / frameworka, aby był połączony z finalnym produkt.

Zaletą używania stałych łańcuchowych zamiast stałych #define'D jest to, że można sprawdzić równość za pomocą porównania wskaźników (stringInstance == MyFirstConstant), które jest znacznie szybsze niż porównanie łańcuchów ([stringInstance isEqualToString:MyFirstConstant]) (i łatwiejsze do odczytania, IMO).

 1249
Author: Barry Wark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-29 11:31:38

Najprostszy sposób:

// Prefs.h
#define PREFS_MY_CONSTANT @"prefs_my_constant"

Lepszy sposób:

// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;

// Prefs.m
NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";

Jedną z zalet drugiej jest to, że zmiana wartości stałej nie powoduje przebudowy całego programu.

 264
Author: Andrew Grant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 22:42:14

Jest jeszcze jedna rzecz, o której warto wspomnieć. Jeśli potrzebujesz stałej nie globalnej, powinieneś użyć słowa kluczowego static.

Przykład

// In your *.m file
static NSString * const kNSStringConst = @"const value";

Ze względu na słowo kluczowe static, const nie jest widoczny poza plikiem.


Drobne poprawki by @ QuinnTaylor: zmienne statyczne są widoczne w jednostce kompilacji . Zazwyczaj jest to singiel .plik m (jak w tym przykładzie), ale może cię ugryźć, jeśli zadeklarujesz go w nagłówku, który jest dołączony gdzie indziej, ponieważ po kompilacji pojawią się błędy linkera

 182
Author: kompozer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:26

Zaakceptowana (i poprawna) odpowiedź mówi, że " możesz dołączyć to [stałe.H] plik... w wstępnie skompilowanym nagłówku dla projektu."

Jako początkujący miałem trudności z zrobieniem tego bez dalszego wyjaśnienia - oto jak: w Twoim Yourapnamehere-prefiksie.plik pch (jest to domyślna nazwa wstępnie skompilowanego nagłówka w Xcode), zaimportuj swoje stałe.h wewnątrz #ifdef __OBJC__ bloku.
#ifdef __OBJC__
  #import <UIKit/UIKit.h>
  #import <Foundation/Foundation.h>
  #import "Constants.h"
#endif

Zauważ również, że stałe.h i stałe.pliki m powinny zawierać absolutnie nic innego w nich poza tym, co jest opisane w zaakceptowanej odpowiedzi. (Brak interfejsu ani implementacji).

 117
Author: Victor Van Hee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-31 17:56:33

Ogólnie używam sposobu zamieszczonego przez Barry ' ego Warka i Rahula Guptę.

Chociaż nie lubię powtarzać tych samych słów w obu .h i .plik M. Zauważ, że w poniższym przykładzie linia jest prawie identyczna w obu plikach:
// file.h
extern NSString* const MyConst;

//file.m
NSString* const MyConst = @"Lorem ipsum";

Dlatego lubię używać maszyn Preprocesorowych C. Pozwól, że wyjaśnię na przykładzie.

Mam plik nagłówkowy, który definiuje makro 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

W moim .h/.Para m, w której chcę zdefiniować stała wykonuję następujące czynności:

// 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, mam wszystkie informacje o stałych w .tylko plik H.

 50
Author: Krizz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-06 01:17:37

Niewielka modyfikacja sugestii @Krizz, tak aby działała poprawnie, jeśli stały plik nagłówkowy ma być dołączony do PCH, co jest raczej normalne. Ponieważ oryginał jest importowany do PCH, nie załaduje go ponownie do pliku .m, a więc nie otrzymasz żadnych symboli i linker jest niezadowolony.

Jednak poniższa modyfikacja pozwala na jej działanie. Trochę zawiłe, ale działa.

Będziesz potrzebował 3 pliki, .h plik, który ma stałą definicje, plik .h i plik .m, użyję ConstantList.h, Constants.h i Constants.m, odpowiednio. zawartość Constants.h to po prostu:

// Constants.h
#define STR_CONST(name, value) extern NSString* const name
#include "ConstantList.h"

A plik Constants.m wygląda następująco:

// Constants.m
#ifdef STR_CONST
    #undef STR_CONST
#endif
#define STR_CONST(name, value) NSString* const name = @ value
#include "ConstantList.h"

Wreszcie, plik ConstantList.h zawiera rzeczywiste deklaracje i to wszystko:

// ConstantList.h
STR_CONST(kMyConstant, "Value");
…

Kilka rzeczy do zapamiętania:

  1. Musiałem przedefiniować makro w pliku .m Po #undefw celu wykorzystania makra.

  2. Miałem też do użycia #include zamiast #import aby to działało poprawnie i aby kompilator nie widział wcześniej wstępnie skompilowanych wartości.

  3. Będzie to wymagało przekompilowania twojego PCH (i prawdopodobnie całego projektu) za każdym razem, gdy jakiekolwiek wartości zostaną zmienione, co nie ma miejsca, jeśli są rozdzielone (i zduplikowane) jak zwykle.

Mam nadzieję, że to jest pomocne dla kogoś.

 25
Author: Scott Little,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-03 00:03:57

Ja sam mam nagłówek dedykowany do deklarowania stałych NSStrings używanych do preferencji jak tak:

extern NSString * const PPRememberMusicList;
extern NSString * const PPLoadMusicAtListLoad;
extern NSString * const PPAfterPlayingMusic;
extern NSString * const PPGotoStartupAfterPlaying;
/ Align = "left" / plik 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";
To podejście dobrze mi służyło.

Edit: zauważ, że działa to najlepiej, jeśli ciągi znaków są używane w wielu plikach. Jeśli używa go tylko jeden plik, możesz po prostu zrobić #define kNSStringConstant @"Constant NSString" w .m plik, który używa ciągu znaków.

 25
Author: MaddTheSane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-26 04:22:08
// Prefs.h
extern NSString * const RAHUL;

// Prefs.m
NSString * const RAHUL = @"rahul";
 14
Author: rahul gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-28 16:19:44

Jak powiedział Abizer, możesz umieścić go w pliku PCH. Innym sposobem, który nie jest tak brudny, jest utworzenie pliku nagłówkowego dla wszystkich kluczy, a następnie dołączenie go do pliku, którego używasz, lub dołączenie go do PCH. Z nimi w ich własnym pliku nagłówkowym, co daje przynajmniej jedno miejsce do szukania i definiowania wszystkich tych stałych.

 12
Author: Grant Limberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 22:05:55

Jeśli chcesz coś w rodzaju stałych globalnych; szybkim brudnym sposobem jest umieszczenie deklaracji stałych w pliku pch.

 11
Author: Abizern,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-07 09:04:36

Używam klasy singleton, więc mogę wyśmiewać klasę i zmieniać stałe, jeśli jest to konieczne do testowania. Klasa stałych wygląda tak:

#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

I jest używany w ten sposób (zwróć uwagę na użycie skrótu dla stałych c-zapisuje wpisywanie [[Constants alloc] init] za każdym razem):

#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
 7
Author: Howard Lovatt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-16 00:00:35

Spróbuj użyć metody klasy:

+(NSString*)theMainTitle
{
    return @"Hello World";
}
Używam go czasami.
 7
Author: groumpf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-31 17:55:33

Jeśli podoba Ci się stała przestrzeni nazw, możesz wykorzystać struct, Friday Q&A 2011-08-19: stałe i funkcje przestrzeni nazw

// 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"
};
 7
Author: onmyway133,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-12 11:54:11