Was ist der beste Weg, um Konstanten in Objective-C zu erstellen?

156

Ich erstelle einen Reddit-Client für Lernzwecke. Ich brauche eine Datei mit Konstanten. Ich habe darüber nachgedacht, die Datei in die Reddit-Prefix.pchDatei zu importieren , um die Konstanten für alle Dateien verfügbar zu machen. Ist es eine gute Art, Dinge zu tun? Außerdem habe ich meine Recherchen durchgeführt und verschiedene Methoden zum Erstellen von Konstanten gefunden, aber ich weiß nicht, welche ich verwenden soll:

  • #define Makro
  • const
  • static const
  • extern const
  • enum

Welcher Weg ist der bevorzugte Weg? Was ist die Konvention? Ich weiß, dass "es darauf ankommt", aber meine Frage lautet genauer: Was sind die Anwendungsfälle für jede dieser Lösungen?

extern constMuss ich bei Verwendung die Datei importieren, sonst sind die Konstanten global verfügbar, ohne die Datei zu importieren?

Eine Sache, die ich logischerweise schließen könnte, ist, dass dies enumdie beste Wahl ist, wenn Sie so etwas wie benutzerdefinierte Fehlerdomänen definieren (habe ich tatsächlich Recht?). Aber was ist mit den anderen?

Robert Audi
quelle
stackoverflow.com/questions/11153156/… Bitte besuchen Sie diesen Link ... Ihre Lösung befindet sich in diesem Beitrag
Benutzer 1531343
3
@ BhavikKama: Das ist eine engere Frage, die zwei spezifische Lösungen gegenüberstellt.
Peter Hosey
Für - static const, #define, enum ist dieser Link nützlich. stackoverflow.com/questions/1674032/static-const-vs-define-in-c bietet eine gute Erklärung für diese 3 Alternativen von const
User 1531343
enumist nur für ganzzahlige Werte nützlich. #defineund Konstanten können ein beliebiger Datentyp sein.
rmaddy
const,, static constund extern constsind bis auf den Umfang alle gleich. Es gibt also wirklich nur drei Möglichkeiten.
rmaddy

Antworten:

385

Die erste Frage ist, welchen Umfang Ihre Konstanten haben sollen. Das sind eigentlich zwei Fragen:

  • Sind diese Konstanten für eine einzelne Klasse spezifisch oder ist es sinnvoll, sie in der gesamten Anwendung zu haben?
  • Wenn sie klassenspezifisch sind, können sie von Clients der Klasse oder nur innerhalb der Klasse verwendet werden?

Wenn sie spezifisch und intern für eine einzelne Klasse sind, deklarieren Sie sie wie static constoben in der .m-Datei wie folgt:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Wenn sie sich auf eine einzelne Klasse beziehen, aber öffentlich sein / von anderen Klassen verwendet werden sollen, deklarieren Sie sie wie externim Header und definieren Sie sie in der .m:

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Wenn sie global sein sollen, deklarieren Sie sie in einem Header und definieren Sie sie in einem entsprechenden Modul, speziell für diese Konstanten.

Sie können diese für verschiedene Konstanten mit unterschiedlichen Ebenen, wie global sie sein sollen, und für verschiedene globale Konstanten, die einfach nicht zusammengehören, mischen und abgleichen. Wenn Sie möchten, können Sie sie in separate Module mit jeweils einem eigenen Header einfügen wollen.

Warum nicht #define?

Die alte Antwort lautet: "Makros haben keine Typinformationen", aber Compiler sind heutzutage ziemlich schlau darin, alle Typprüfungen auf Literale (auf die Makros erweitert werden) und Variablen durchzuführen.

Die moderne Antwort ist, dass der Debugger nichts über Ihre Makros weiß. Sie können [myThing addObserver:self forKey:MyThingNotificationKey]in einem Debugger-Befehl nicht sagen, ob MyThingNotificationKeyes sich um ein Makro handelt. Der Debugger kann nur wissen, ob es sich um eine Variable handelt.

Warum nicht enum?

Nun, rmaddy hat mich in den Kommentaren geschlagen: enumKann nur ganzzahlige Konstanten definieren. Dinge wie Seriennummern, Bitmasken, Vier-Byte-Codes usw.

Für diese Zwecke enumist großartig und Sie sollten es unbedingt verwenden. (Noch besser ist , verwenden Sie die NS_ENUMund NS_OPTIONSMakros .) Für andere Dinge, Sie müssen etwas anderes nutzen; enummacht nichts anderes als ganze Zahlen.

Und andere Fragen

Ich habe darüber nachgedacht, die Datei in die Datei Reddit-Prefix.pch zu importieren, um die Konstanten für alle Dateien verfügbar zu machen. Ist es eine gute Art, Dinge zu tun?

Wahrscheinlich harmlos, aber wahrscheinlich übertrieben. Importieren Sie Ihre Konstanten-Header dort, wo Sie sie benötigen.

Was sind die Anwendungsfälle für jede dieser Lösungen?

  • #define: Ziemlich begrenzt. Ich bin mir ehrlich gesagt nicht sicher, ob es einen guten Grund mehr gibt, dies für Konstanten zu verwenden.
  • const: Am besten für lokale Konstanten. Außerdem müssen Sie dies für eine verwenden, die Sie in einem Header deklariert haben und jetzt definieren.
  • static const: Am besten für dateispezifische (oder klassenspezifische) Konstanten.
  • extern const: Sie müssen dies verwenden, wenn Sie eine Konstante in einen Header exportieren.

extern constMuss ich bei Verwendung die Datei importieren, sonst sind die Konstanten global verfügbar, ohne die Datei zu importieren?

Sie müssen die Datei entweder in jede Datei, in der Sie sie verwenden, oder in den Präfix-Header importieren.

Peter Hosey
quelle
3
Warum nicht insgesamt static NSString *constin der .hDatei verwenden?
Iulian Onofrei
3
@IulianOnofrei: Sie können, wenn es sich um eine Anwendung und nicht um ein Framework handelt. Wenn Sie dies tun static NSString *const foo = @"foo";, bestimmt Ihr Header, was die Zeichenfolge ist, und sie muss überall gleich sein. Wenn Sie die Zeichenfolge jemals ändern und verschiedene Parteien unterschiedliche Versionen des Headers mit einer anderen Zeichenfolge verwenden, stimmen die Zeichenfolgen beim Ausführen nicht überein Zeit. In einem Framework möchten Sie nur Zugriff auf das Symbol gewähren und das Framework als einzige Quelle für den wahren Wert dieses Symbols verwenden, damit jeder an einer Stelle dieselbe Zeichenfolge erhält. Das externbringt dich.
Peter Hosey
Zusätzlicher Hinweis zu #defines: Es wird nicht garantiert, dass sie dieselbe Adresse im Speicher haben (je nachdem, wie sie deklariert sind, können sie bei jeder Verwendung eine neue Instanz zuweisen), sodass die Verwendung myObject == MyDefinenicht immer wie erwartet funktioniert. aber myObject == MyStaticConstwird.
Ben Leggiero
Ist es sinnvoll, wie static NSString *conststatt zu buchstabieren static NSString const*? Irgendwelche Unterschiede ?!
Kokos8998
@ kokos8998 macht es einen Unterschied? Ja tut es. static NSString const *ist dasselbe wie static const NSString *und bedeutet "ein (veränderbarer) Zeiger auf einen konstanten NSString" - was hier etwas nutzlos ist, da NSString bereits unveränderlich ist. Was Sie nur wollen static NSString * const- was ein "konstanter Zeiger auf einen NSString" ist
David
8

FOUNDATION_EXPORT

Erwägen Sie die Verwendung FOUNDATION_EXPORTfür etwas mehr Kompatibilität als externin Foundation definiert und in kompatiblen Formaten für C, C ++ und Win32 kompiliert.

Wie in NSObjCRuntime.h definiert

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif

#if TARGET_OS_WIN32

    #if defined(NSBUILDINGFOUNDATION)
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
    #else
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
    #endif

    #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)

#else
    #define FOUNDATION_EXPORT  FOUNDATION_EXTERN
    #define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif
Steve Moser
quelle