Domanda

Sto imparando l'obiettivo C e il cacao e mi sono imbattuto in questa affermazione:

I framework Cocoa prevedono che vengano utilizzate costanti di stringa globali anziché valori letterali di stringa per le chiavi del dizionario, i nomi di notifiche ed eccezioni e alcuni parametri di metodo che accettano stringhe.

Ho lavorato solo con linguaggi di livello superiore, quindi non ho mai dovuto considerare così tanto i dettagli delle stringhe.Qual è la differenza tra una costante di stringa e un valore letterale di stringa?

È stato utile?

Soluzione

In Objective-C, la sintassi @"foo" è un immutabile, letterale istanza di NSString.Non crea una stringa costante da una stringa letterale come presume Mike.

Tipicamente compilatori Objective-C Fare interna stringhe letterali all'interno delle unità di compilazione, ovvero uniscono più usi della stessa stringa letterale, ed è possibile per il linker eseguire un ulteriore internamento tra le unità di compilazione direttamente collegate in un singolo binario.(Poiché Cocoa distingue tra stringhe mutabili e immutabili e anche le stringhe letterali sono sempre immutabili, questo può essere semplice e sicuro.)

Costante le stringhe d'altro canto vengono tipicamente dichiarate e definite utilizzando una sintassi come questa:

// MyExample.h - declaration, other code references this
extern NSString * const MyExampleNotification;

// MyExample.m - definition, compiled for other code to reference
NSString * const MyExampleNotification = @"MyExampleNotification";

Il punto dell'esercizio sintattico qui è che puoi fare usi di la stringa efficiente garantendo che ci sia solo un'istanza di quella stringa in uso anche su più framework (librerie condivise) nello stesso spazio di indirizzi.(Il posizionamento del const le parole chiave sono importanti;garantisce che il puntatore stesso sia garantito essere costante.)

Sebbene bruciare memoria non sia un grosso problema come potrebbe essere stato ai tempi delle workstation 68030 da 25 MHz con 8 MB di RAM, confrontare le stringhe per l'uguaglianza può richiedere tempo.Garantire che la maggior parte delle volte le stringhe uguali siano anche uguali al puntatore aiuta.

Supponiamo, ad esempio, che desideri iscriverti alle notifiche di un oggetto in base al nome.Se utilizzi stringhe non costanti per i nomi, il file NSNotificationCenter pubblicare la notifica potrebbe comportare molti confronti di stringhe byte per byte per determinare chi è interessato.Se la maggior parte di questi confronti vengono cortocircuitati perché le stringhe confrontate hanno lo stesso puntatore, ciò può essere una grande vittoria.

Altri suggerimenti

Alcune definizioni

UN letterale è un valore, che è immutabile per definizione.per esempio: 10
UN costante è una variabile o puntatore di sola lettura.per esempio: const int age = 10;
UN stringa letterale è un'espressione come @"".Il compilatore lo sostituirà con un'istanza di NSString.
UN costante di stringa è un puntatore di sola lettura a NSString.per esempio: NSString *const name = @"John";

Alcuni commenti sull'ultima riga:

  • Questo è un puntatore costante, non un oggetto costante1. objc_sendMsg2 non importa se qualifichi l'oggetto con const.Se vuoi un oggetto immutabile, devi codificare quell'immutabilità all'interno dell'oggetto3.
  • Tutto @"" le espressioni sono infatti immutabili.Vengono sostituiti4 in fase di compilazione con istanze di NSConstantString, che è una sottoclasse specializzata di NSString con un layout di memoria fisso5.Questo spiega anche il perché NSString è l'unico oggetto che può essere inizializzato in fase di compilazione6.

UN stringa costante sarebbe const NSString* name = @"John"; che è equivalente a NSString const* name= @"John";.Qui, sia la sintassi che l'intenzione del programmatore sono sbagliate: const <object> viene ignorato e il NSString istanza (NSConstantString) era già immutabile.

1 La parola chiave const si applica si applica a tutto ciò che è immediatamente alla sua sinistra.Se non c'è nulla alla sua sinistra, si applica a tutto ciò che è immediatamente alla sua destra.

2 Questa è la funzione che il runtime utilizza per inviare tutti i messaggi in Objective-C e quindi ciò che puoi utilizzare per modificare lo stato di un oggetto.

3 Esempio:In const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects]; const non impedisce l'ultima istruzione.

4 Il codice LLVM che riscrive l'espressione è RewriteModernObjC::RewriteObjCStringLiteral in RewriteModernObjC.cpp.

5 Per vedere il NSConstantString definizione, cmd+fai clic su di esso in Xcode.

6 Creare costanti di tempo di compilazione per altre classi sarebbe facile ma richiederebbe al compilatore di utilizzare una sottoclasse specializzata.Ciò interromperebbe la compatibilità con le versioni precedenti di Objective-C.


Torniamo al tuo preventivo

I framework di cacao si aspettano che le costanti di stringa globali piuttosto che i letterali di stringa siano usati per chiavi del dizionario, nomi di notifica e eccezioni e alcuni parametri del metodo che prendono stringhe.Dovresti sempre preferire le costanti di stringa sui letterali delle stringhe quando hai una scelta.Usando le costanti di stringa, si chiede l'aiuto del compilatore per controllare l'ortografia e quindi evitare errori di runtime.

Dice che i letterali sono soggetti a errori.Ma non è detto che siano anche più lenti.Confrontare:

// string literal
[dic objectForKey:@"a"];

// string constant
NSString *const a = @"a";
[dic objectForKey:a];

Nel secondo caso sto usando chiavi con puntatori const, quindi invece [a isEqualToString:b], Posso fare (a==b).L'implementazione di isEqualToString: confronta l'hash e quindi esegue la funzione C strcmp, quindi è più lento rispetto al confronto diretto dei puntatori.Che è perché le stringhe costanti sono migliori: sono più veloci da confrontare e meno soggetti a errori.

Se vuoi che anche la tua stringa costante sia globale, fallo in questo modo:

// header
extern NSString *const name;
// implementation
NSString *const name = @"john";

Usiamo C++, poiché il mio Objective C è totalmente inesistente.

Se nascondi una stringa in una variabile costante:

const std::string mystring = "my string";

Ora quando chiami metodi, usi my_string, stai usando una costante stringa:

someMethod(mystring);

Oppure puoi chiamare direttamente questi metodi con la stringa letterale:

someMethod("my string");

Il motivo, presumibilmente, per cui ti incoraggiano a utilizzare costanti stringa è perché Objective C non esegue l'"internamento";cioè, quando usi la stessa stringa letterale in più posti, in realtà è un puntatore diverso che punta a una copia separata della stringa.

Per le chiavi del dizionario, questo fa un'enorme differenza, perché se riesco a vedere che i due puntatori puntano alla stessa cosa, è molto più economico che dover fare un confronto tra stringhe intere per assicurarsi che le stringhe abbiano lo stesso valore.

Modificare: Mike, in C# le stringhe sono immutabili e le stringhe letterali con valori identici terminano tutte con lo stesso valore di stringa.Immagino che sia vero anche per altre lingue che hanno stringhe immutabili.In Ruby, che ha stringhe mutabili, offrono un nuovo tipo di dati:simboli ("foo" vs.:foo, dove la prima è una stringa mutabile e il secondo è un identificatore immutabile spesso utilizzato per le chiavi Hash).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top