2010-10-15 5 views
0

Je souhaite convertir un NSString en un const char * afin d'accéder à une base de données sqlite.Crash de l'application iPhone lors de la conversion de NSString au format UTF8 char *

Cela fonctionne:

NSString *queryStatementNS = @"select title from article limit 10"; 
const char *queryStatement = [queryStatementNS UTF8String]; 

Cela provoque un accident dans le simulateur (sans stacktrace):

NSString *queryStatementNS = [NSString stringWithFormat:@"select title from article limit %d", 10]; 
const char *queryStatement = [queryStatementNS UTF8String]; 

Quelqu'un peut-il me dire, quels sont les changements de méthode de stringWithFormat dans la chaîne pour faire la conversion à UTF8 (ou ASCII en utilisant cStringUsingEncoding: NSASCIIStringEncoding) crash? Le même crash se produit également lors de la transmission d'aucun argument au stringWithFormat. Pourrait-il être lié à la gestion de la mémoire en quelque sorte?

+1

L'appel stringWithFormat est-il dans un endroit ou une méthode différent de la méthode UTF8String? Si c'est le cas, l'objet autorelease queryStatementNS dans le deuxième exemple aurait pu être libéré. Le premier exemple utilise une constante, qui n'est pas un objet autorelease. – hotpaw2

+0

Tout était dans un seul endroit, tout comme dans l'exemple. Cependant, j'ai ajouté un [queryStatementNS retain]; entre ces lignes et maintenant cela fonctionne. – Sven

Répondre

0

De la documentation:

La chaîne C retour est automatiquement libéré comme un objet retourné serait être libéré; vous devez copier la chaîne C si elle doit la stocker en dehors de du contexte autorelease dans lequel la chaîne C est créée.

Votre problème est que queryStatement est libéré quand queryStatementNS sera désallouée, et comme queryStatementNS est autoreleased vous ne savez pas exactement quand cela va se produire. Vous pouvez conserver queryStatementNS en appelant

[queryStatementNS retain] 

à un moment donné dans cette fonction (souvenez-vous de le libérer lorsque vous souhaitez renoncer à la propriété), vous pouvez créer explicitement une chaîne non autoreleased à traiter avec vous-même en disant

NSString* query = [[NSString alloc] initWithFormat:@"a string! %d", 10, nil] 

(en aparté, notez le nul - si vous ne l'avez pas, il Xcode vous donnera un avertissement sentinelle manquante)

ou vous pouvez copier la sortie de [queryStatementNS UTF8String] à votre const char * queryStatement comme vous le feriez en C simple , avec strcopy ou autre.

La raison pour laquelle le premier exemple que vous donnez continue de fonctionner est que vous définissez un pointeur sur un littéral de chaîne, "sélectionnez le titre de la limite d'article 10". Le compilateur c d'objectif s'assure qu'il y a seulement une instance de cette chaîne dans la mémoire, peu importe combien de fois vous le référencez dans votre code. Ainsi, il n'obéit pas aux conventions de gestion de la mémoire standard de l'objectif c et votre pointeur reste valide en dehors du contexte auto-libéré.

+0

Merci pour votre réponse, je vais essayer d'adopter mon code demain. L'allocation et la désallocation de la mémoire sont confuses quand vous venez de Java (j'avais l'habitude d'écrire du code C il y a plus de 12 ans pour la dernière fois ...). Cela réglerait-il aussi mon problème si je déclarais NSString dans mon fichier .h et déclarais un paramètre @ (nonatomic, retain) dessus? Je pensais que je devais libérer le queryStatementNS * manuellement * comme je l'ai défini localement dans ma méthode et n'avais aucune idée du concept autorelease ici. J'ai vraiment besoin de lire plus sur cette chose alloc/retain/release. Merci! – Sven

+0

Oui, conserver NSString en tant que variable d'instance résoudrait votre problème. Assurez-vous de le libérer dans la méthode dealloc! – johnw188

Questions connexes