views:

64

answers:

1

I want to convert a NSString into a const char * in order to access a sqlite DB.

This works:

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

This causes a crash in the simulator (without any stacktrace):

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

Can anybody tell me, what the stringWithFormat method changes in the String to make the conversion to UTF8 (or to ASCII using cStringUsingEncoding:NSASCIIStringEncoding) crash? The same crash happens also when passing no arg at all to the stringWithFormat. Could it be related to memory management somehow?

A: 

From the documentation:

The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.

Your problem is that queryStatement is being freed when queryStatementNS gets deallocated, and as queryStatementNS is autoreleased you don't know exactly when this is going to occur. You can either retain queryStatementNS by calling

[queryStatementNS retain]

at some point in that function (remember to release it when you want to relinquish ownership), you can explicitly create a non-autoreleased string to deal with yourself by saying

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

(as an aside, note the nil - if you don't have it there xcode will give you a missing sentinel warning)

or you can copy the output of [queryStatementNS UTF8String] to your const char* queryStatement as you would in plain C, with strcopy or whatever.

The reason the first example you give continues to work is that you're setting a pointer to a string literal, @"select title from article limit 10". The objective c compiler ensures that there's only ever one instance of this string in memory, no matter how many times you reference it in your code. Thus, it doesn't obey the standard memory management conventions of objective c and your pointer remains valid outside of the autoreleased context.

johnw188
Thank you for your answer, I will try to adopt my code tomorrow. The whole memory allocation and deallocation is confusing when you're coming from Java (I used to write C code more than 12 years ago for the last time...). Would it also fix my problem if I would declare the NSString in my .h file and declare a @parameter(nonatomic,retain) on it? I thought that I had to release the queryStatementNS *manually* as I defined it locally in my method and had and no idea about the autorelease concept here.; I really need to read more on this alloc/retain/release thing. Thanks!
Sven
Yes, retaining the NSString as an instance variable would solve your problem. Be sure to release it in the dealloc method!
johnw188