2009-12-08 16 views
11

Ich habe ein Protokoll definiert, das alle meine Plug-Ins implementieren müssen. Ich möchte auch, dass alle Plug-Ins bestimmte Zeichenfolgen verwenden, wie MyPluginErrorDomain. Mit Ganzzahlen ist das ziemlich einfach in einem Enum zu erreichen, aber ich kann nicht herausfinden, wie man dasselbe mit Strings macht. Normalerweise in Klassen würde ichWas ist der beste Weg, um String-Konstanten in einem Ziel-C-Protokoll zu definieren?

extern NSString * const MyPluginErrorDomain; 

in der H-Datei und in der .m-Datei definieren:

NSString * const MyPluginErrorDomain = @"MyPluginErrorDomain"; 

aber die sehr gut in einem Protokoll nicht funktioniert, weil dann jeder Plug- in müsste eine eigene Implementierung bereitstellen, die den Zweck einer Konstanten vereitelt.

Ich habe dann versucht

#define MYPLUGIN_ERROR_DOMAIN @"MyPluginErrorDomain" 

aber die Umsetzung der Klassen in der Plug-in kann nicht scheinen, die #define zu sehen. Wer kennt eine gute Lösung?

+0

entfernen C, C++ Tags - das ist objektive C Frage – zaharpopov

+0

Für das C++ bemerkt, siehe auch meinen Kommentar zu Neil Butterworth's interessante Antwort. Ich frage mich immer noch, ob es auch keine C-Lösung gibt, ich kann nicht die erste Person in der Geschichte von C sein, die das erreichen wollte. –

+0

Da dies C-Konstanten sind, musste dieses C nicht entfernt werden – iCaramba

Antwort

10

Sie können sie im Header mit dem Protokoll deklarieren (aber außerhalb der Protokollschnittstelle selbst), dann definiert sie in einer Implementierungsdatei für das Protokoll (natürlich wäre es nicht einen @implementation Abschnitt hat - nur Ihre NSString Definitionen).

Oder haben Sie ein separates .h/.m-Paar, das nur für die String-Konstanten ist (der Protokoll-Header kann den String-Konstanten-Header importieren).

3

In C++, würde ich sie in einem Header wie folgt erklären:

const char * const MYPLUGIN_ERROR_DOMAIN = "MyPluginErrorDomain"; 
const char * const MYPLUGIN_FOO_DOMAIN = "MyPluginFooDomain"; 

Beachten Sie, dass als die Zeiger const sind, werden sie auf die Übersetzungseinheiten lokal sein wird der Header #include in, und so gibt Sie müssen extern nicht verwenden, um mehrere Definitionsfehler zu vermeiden.

+0

Ist * lokal für die Übersetzungseinheiten * gültig für alle Const-Pointer-Definitionen? –

+1

Es gilt für alle const-Definitionen - Zeiger sind nur ein Fall. Beachten Sie, dass der Zeiger selbst const sein muss, also const char * p = "foo"; würde ich nicht tun. –

+0

Für diejenigen, die wie ich überraschend fanden: "Ein Name mit Namespace-Bereich hat interne Verknüpfung, wenn es der Name von .. ist ein Objekt oder eine Referenz, die explizit Const deklariert wird und weder explizit extern deklariert .." [3.5/3 ] –

9

Sie halten die .h Definition:

extern NSString * const MyPluginErrorDomain; 

aber diesen Teil in eine separate .m-Datei setzen, die in Ihrem Rahmen eingeschlossen wird:

NSString * const MyPluginErrorDomain = @"MyPluginErrorDomain"; 

So können Plug-Ins noch die Umsetzung Schnittstelle, aber beim Kompilieren verknüpfen oder kompilieren sie in Ihrer anderen .m-Datei, so dass sie den Wert MyPluginErrorDomain sehen.

2

Sie sollten es als externe Strings wie in Ihrem Beispiel implementieren:

extern NSString * const MyPluginErrorDomain;

oder externe Funktionen bereitstellen, die statische Speicherdaten zurückgeben. Zum Beispiel:

/* h */ 

extern NSString * MyPluginErrorDomain(); 

/* m */ 

NSString * MyPluginErrorDomain() { 
    static NSString * const s = @"MyPluginErrorDomain"; 
    return s; 
} 

Der Grund dafür ist, dass Strings und Schlüssel werden häufig verwendet und verglichen mit Zeigerwert oder Hash-Wert, anstatt echtem String-Vergleich (isEqualToString :).

auf Implementierungsebene gibt es einen großen Unterschied zwischen:

In Code, das heißt, dass, wenn die in mehreren Binärdateien definiert verglichen Strings werden:

Say ‚MyPluginErrorDomain‘ und ‚Schlüssel‘ identisch haben String-Werte, sind aber in verschiedenen Binaries definiert (dh im Plugin-Host, im Plug-in).

/////// Pointer comparison (NSString) 
BOOL a = [MyPluginErrorDomain isEqualToString:key]; 
BOOL b = MyPluginErrorDomain == key; 

// c may be false because a may be true, in that they represent the same character sequence, but do not point to the same object 
BOOL c = a == b; 


/////// Hash use (NSString) 
// This is true 
BOOL d = [MyPluginErrorDomain hash] == [key hash]; 

// This is indicative if true 
BOOL e = [MyPluginErrorDomain hash] == [someOtherStringKey hash]; 

// because 
BOOL f = [MyPluginErrorDomain isEqualToString:someOtherStringKey]; 

// g may be false (though the hash code is 'generally' correct) 
BOOL g = e == f; 

Daher müssen in vielen Fällen die Schlüssel zur Verfügung gestellt werden. Es mag wie ein trivialer Punkt erscheinen, aber es ist schwierig, einige der mit dem Unterschied verbundenen Probleme zu diagnostizieren.

Hash-Codes und Zeigervergleiche werden überall in Foundation und anderen Objc-Technologien in den Interna von Dictionary-Speicher, Schlüsselwertcodierung verwendet ... Wenn Ihr Wörterbuch direkt nach xml geht, ist das eine Sache, aber die Laufzeit ist eine andere und In den Details zur Implementierung und zur Laufzeit gibt es einige Einschränkungen.

+0

'extern'-Strings funktionieren nicht, da Sie keine Verbindung zu einer Binärdatei herstellen müssen, um mit ihr über ein' Protokoll' zu kommunizieren - think * remote messaging * –

+0

@gf Es ist nicht ungewöhnlich, dass ein Plugin mit einer Bibliothek verknüpft an die Plugin-Schnittstelle. – justin

+0

* "Nicht ungewöhnlich" * ist nicht * "immer" * - Remote-Messaging ist auch * "üblich" mit Cocoa. –

Verwandte Themen