iPhone app crash when converting formatted NSString to UTF8 char * - iphone

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?

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.

Related

iOS - libical / const char * - memory usage

I am using the libical library to parse the iCalendar format and read the information I need out of it. It is working absolutely fine so far, but there is one odd thing concerning ical.
This is my code:
icalcomponent *root = icalparser_parse_string([iCalData cStringUsingEncoding:NSUTF8StringEncoding]);
if (root)
{
icalcomponent *currentEvent = icalcomponent_get_first_component(root, ICAL_VEVENT_COMPONENT);
while (currentEvent)
{
while(currentProperty)
{
icalvalue *value = icalproperty_get_value(currentProperty);
char *icalString = icalvalue_as_ical_string_r(value); //seems to leak
NSString *currentValueAsString = [NSString stringWithCString:icalString
encoding:NSUTF8StringEncoding];
icalvalue_free(value);
//...
//import data
//...
icalString = nil;
currentValueAsString = nil;
icalproperty_free(currentProperty);
currentProperty = icalcomponent_get_next_property(currentEvent, ICAL_ANY_PROPERTY);
} //end while
} //end while
icalcomponent_free(currentEvent);
}
icalcomponent_free(root);
//...
I did use instruments to check my memory usage and were able to find out, that this line seems to leak:
char *icalString = icalvalue_as_ical_string_r(value); //seems to leak
If I'd copy and paste this line 5 or six times my memory usage would grow about 400kb and never get released anymore.
There is no free method for the icalvalue_as_ical_string_r method because it's returning a char *..
Any suggestions how to solve this issue? I would appreciate any help!
EDIT
Taking a look at the apple doc says the following:
To get a C string from a string object, you are recommended to use UTF8String. This returns a const char * using UTF8 string encoding.
const char *cString = [#"Hello, world" UTF8String];
The C string you receive is owned by a temporary object, and will become invalid when automatic deallocation takes place. If you want to get a permanent C string, you must create a buffer and copy the contents of the const char * returned by the method.
But how to release a char * string properly now if using arc?
I tried to add #autorelease {...} in front of my while-loop but without any effort. Still increasing memory usage...
Careful with the statement "no free method...because it's returning a char*"; that is never something you can just assume.
In the absence of documentation you can look at the source code of the library to see what it does; for example:
http://libical.sourcearchive.com/documentation/0.44-2/icalvalue_8c-source.html
Unfortunately this function can do a lot of different things. There are certainly some cases where calling free() on the returned buffer would be right but maybe that hasn't been ensured in every case.
I think it would be best to request a proper deallocation method from the maintainers of the library. They need to clean up their own mess; the icalvalue_as_ical_string_r() function has at least a dozen cases in a switch that might have different deallocation requirements.
icalvalue_as_ical_string_r returns a char * because it has done a malloc() for your result string. If your pointer is non-NULL, you have to free() it after use.

how to define a returning NSString function in Objective-C / Xcode using a temporary variable?

I would like to define the following function in Objective-C. I have provided pseudo-code to help illustrate what I'm trying to do.
PSEUDOCODE:
function Foo(param) {
string temp;
if(param == 1) then
temp = "x";
else if(param == 2) then
temp = "y";
else if(param == 3) then
temp = "z";
else
temp = "default";
end if
return temp;
}
For some reason if I do this... the variable who I assign it to results in a "BAD Access" error.
I don't know what the difference between:
static NSstring *xx;
or the non-static:
NSString *xx;
declarations are, and how or why I would want to use one over the other.
I also do not fully understand the initializers of NSString, and how they differ. For example:
[[NSString alloc] initWithString:#"etc etc" ];
or the simple assignment:
var = #""
or even:
var = [NSString stringWithString:#"etc etc"];
Can you give me a hand please?
So far, using the NSString value returned from functions like those listed above, always causes an error.
static NSstring *xx;
That declares a statically allocated variable, much like it does in C.
NSstring *xx;
Inside a method that declares a normal local stack variable, just as it does in C.
As you should be aware, the difference between the two is that the first will keep its value between invocations of the function (and can cause trouble if the function is called from multiple threads).
[[NSString alloc] initWithString:#"etc etc"]
That creates a new NSString object, with the contents etc etc. This may or may not be the same as any other NSString object in your program with the same contents, but you don't have to care. Memory management wise, you own it, so you are responsible for ensuring that you eventually call release or autorelease on it to avoid leaking memory.
#"etc etc"
[NSString stringWithString:#"etc etc"]
Those are basically the same. Both give you an NSString object with the contents etc etc. This may or may not be the same as any other NSString object in your program with the same contents, but you don't have to care. Memory management wise, you do not own it, so you must not call release or autorelease on the object unless you first took ownership by calling retain. Also, since you do not own it, you can use it within your method, pass it as a parameter to other methods, and even use it as the return value from your method, but you may not store it in an ivar or static variable without taking ownership by calling retain or making a copy (with copy).
Also, note that "" and #"" are very different. The first gives you a const char * exactly as it does in C, while the second gives you an NSString object. Your program will crash if you use a const char * where the code expects an NSString object.
You can do it this way:
- (NSString *)functionName:(int)param {
NSString *result = nil;
switch (param) {
case 1:
result = [NSString stringWithString:#"x"];
break;
case 2:
result = [NSString stringWithString:#"y"];
break;
case 3:
result = [NSString stringWithString:#"z"];
break;
default:
result = [NSString stringWithString:#"defaultv"];
break;
}
return result;
}
Post real code, not pseudo code, as it makes it much easier to answer your question in concrete terms.
Given that you indicate that you are quite new to Objective-C, I would suggest starting with the language guide and then moving on to the memory management guide.

Encode and Decode using UTF-8 in iPhone

I'm looking for an example demonstrating how I can encode and then decode the same string using UTF-8. Encode and then Decode means I want to implement the methods in 2 areas where one can encode it and another is able to decode it.
I have seen the API but I didn't get much success:
stringWithCString:encoding:
stringWithUTF8String:
stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
EDITED
I have the string øæ-test-2.txt which I am encoding as follows:
char *s = "øæ-test-2.txt";
NSString *enc = [NSString stringWithCString:s encoding:NSASCIIStringEncoding];
but am getting øæ-test-2.txt as output.
Now I want to get back the original string back i.e. øæ-test-2.txt
EDITED
I am getting øæ-test-2.txt from server and I need øæ-test-2.txt by decoding it. I am able to get the output from the link : http://www.cafewebmaster.com/online_tools/utf_decode
Please try to use the link and you will understand my concern.
It would be highly appreciated if anyone can give some hint, tutorial or point me in the right direction.
Regards
To turn an NSString object into a UTF8 C-string, use UTF8String
char *utf8string = [#"A string with ümläuts" UTF8String];
To turn a UTF8 C-string into an NSString object, use stringWithUTF8String: or initWithUTF8String:
NSString *string = [NSString stringWithUTF8String:utf8string];
Note that NSString objects are implemented as UTF-16, so you can't really have a "UTF-8 NSString" (and the encoding should be treated as an implementation detail, anyway).
Instead of
char *utf8string = [#"A string with ümläuts" UTF8String];
This should be
const char *utf8string = [#"A string with ümläuts" UTF8String];
Otherwise you have an incompatible type issue.

When converting a NSString to a char* using UTF8String, how to retain it?

When converting a NSString to a char* using UTF8String, how to retain it?
According to the following link, when you use UTF8String the returned char* is pretty much autoreleased, so it won't last beyond the current function: http://developer.apple.com/mac/library/documentation/cocoa/reference/Foundation/Classes/NSString_Class/Reference/NSString.html#jumpTo_128
It says i have to copy it or something to keep it around. How can i do this?
The reason i ask is that if i do [myCharPointer retain] it doesn't retain it because it's not an obj-c object, it's a c pointer.
Thanks
You can use strdup()
const char* utf8Str = [#"an example string" UTF8String];
if (utf8Str != NULL)
{
stringIWantToKeep = strdup(utf8Str);
}
When you are done with stringIWantToKeep, you free it as though it was originally malloc'd.
Try using -getCString:maxLength:encoding:, e.g.:
NSUInteger bufferCount = sizeof(char) * ([string length] + 1);
const char *utf8Buffer = malloc(bufferCount);
if ([string getCString:utf8Buffer
maxLength:bufferCount
encoding:NSUTF8StringEncoding]) {
NSLog("Success! %s", utf8Buffer);
free(utf8Buffer); // Remember to do this, or you will get a memory leak!
}
If you need an object to retain/release as every other object you can do the following:
NSData* storage= [yourNSString dataUsingEncoding:NSUTF8StringEncoding];
char* yourCString= (char*)storage.bytes;
// your code flow here
Now you can pass both storage and yourCString to any function retaining/releasing storage as you like, when the retain count of storage will go to 0 the memory pointed by yourCString will be freed too.
I used this to keep a single copy of a very long string while having references created by strtok_r in beans and have the memory released only when all beans had been released.
A little note about (missing) BOM:
As stated here http://boredzo.org/blog/archives/2012-06-03/characters-in-nsstring dataUsingEncoding: should add BOM but i've checked with the debugger and there is no BOM in the returned bytes.

NSString stringWithFormat swizzled to allow missing format numbered args

Based on this SO question asked a few hours ago, I have decided to implement a swizzled method that will allow me to take a formatted NSString as the format arg into stringWithFormat, and have it not break when omitting one of the numbered arg references (%1$#, %2$#)
I have it working, but this is the first copy, and seeing as this method is going to be potentially called hundreds of thousands of times per app run, I need to bounce this off of some experts to see if this method has any red flags, major performance hits, or optimizations
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#implementation NSString (UAFormatOmissions)
+ (id)uaStringWithFormat:(NSString *)format, ... {
if (format != nil) {
va_list args;
va_start(args, format);
// $# is an ordered variable (%1$#, %2$#...)
if ([format rangeOfString:#"$#"].location == NSNotFound) {
//call apples method
NSString *s = [[[NSString alloc] initWithFormat:format arguments:args] autorelease];
va_end(args);
return s;
}
NSMutableArray *newArgs = [NSMutableArray arrayWithCapacity:NUMARGS(args)];
id arg = nil;
int i = 1;
while (arg = va_arg(args, id)) {
NSString *f = [NSString stringWithFormat:#"%%%d\$\#", i];
i++;
if ([format rangeOfString:f].location == NSNotFound) continue;
else [newArgs addObject:arg];
}
va_end(args);
char *newArgList = (char *)malloc(sizeof(id) * [newArgs count]);
[newArgs getObjects:(id *)newArgList];
NSString* result = [[[NSString alloc] initWithFormat:format arguments:newArgList] autorelease];
free(newArgList);
return result;
}
return nil;
}
The basic algorithm is:
search the format string for the %1$#, %2$# variables by searching for %#
if not found, call the normal stringWithFormat and return
else, loop over the args
if the format has a position variable (%i$#) for position i, add the arg to the new arg array
else, don't add the arg
take the new arg array, convert it back into a va_list, and call initWithFormat:arguments: to get the correct string.
The idea is that I would run all [NSString stringWithFormat:] calls through this method instead.
This might seem unnecessary to many, but click on to the referenced SO question (first line) to see examples of why I need to do this.
Ideas? Thoughts? Better implementations? Better Solutions?
Whoa there!
Instead of screwing with a core method that you very probably will introduce subtle bugs into, instead just turn on "Static Analyzer" in your project options, and it will run every build - if you get the arguments wrong it will issue a compiler warning for you.
I appreciate your desire to make the application more robust but I think it very likely that re-writing this method will more likely break your application than save it.
How about defining your own interim method instead of using format specifiers and stringWithFormat:? For example, you could define your own method replaceIndexPoints: to look for ($1) instead of %1$#. You would then format your string and insert translated replacements independently. This method could also take an array of strings, with NSNull or empty strings at the indexes that don't exist in the “untranslated” string.
Your method could look like this (if it were a category method for NSMutableString):
- (void) replaceIndexPointsWithStrings:(NSArray *) replacements
{
// 1. look for largest index in "self".
// 2. loop from the beginning to the largest index, replacing each
// index with corresponding string from replacements array.
}
Here's a few issues that I see with your current implementation (at a glance):
The __VA_ARGS__ thingy explained in the comments.
When you use while (arg = va_arg(args, id)), you are assuming that the arguments are nil terminated (such as for arrayWithObjects:), but with stringWithFormat: this is not a requirement.
I don't think you're required to escape the $ and # in your string format in your arg-loop.
I'm not sure this would work well if uaStringWithFormat: was passed something larger than a pointer (i.e. long long if pointers are 32-bit). This may only be an issue if your translations also require inserting unlocalised numbers of long long magnitude.