I have a NSMutableDictionary holding EXIF metadata from a picture.
An example:
const CFStringRef kCGImagePropertyExifExposureTime;
Instead of accessing every key individually, I just want write the whole dictionary content into a label.
When I want to write this data into the console I would just use:
NSLog(#"EXIF Dic Properties: %#",EXIFDictionary );
That works fine, but if I use:
NSString *EXIFString = [NSString stringWithFormat:(#"EXIF Properties: %#", EXIFDictionary)];
I get warnings that the result is not a string literally and if I try to use that string to set my label.text, the program crashes.
Any idea where my error is?
[NSString stringWithFormat:(#"EXIF Properties: %#", EXIFDictionary)] is not, as you may think, a method with two arguments. It's a method with one argument. That one argument is (#"EXIF Properties: %#", EXIFDictionary), which uses the comma operator and ends up returning EXIFDictionary. So in essence you have
[NSString stringWithFormat:EXIFDictionary]
which is obviously wrong. This is also why you're getting a warning. That warning tells you that the format argument is not a string literal, because using variables as format strings is a common source of bugs. But more importantly here, that argument isn't even a string at all, and so it crashes.
Remove the parentheses and everything will be fine. That will look like
[NSString stringWithFormat:#"EXIF Properties: %#", EXIFDictionary];
I get warnings that the result is not a string literally
Nah. You get a warning saying that the format string of stringWithFormat: is not a string literal. That's because you don't know how the comma operator (and a variadic function) works (that's why one should master the C language before trying to make an iOS app). Basically what you have here:
[NSString stringWithFormat:(#"EXIF Properties: %#", EXIFDictionary)]
is, due the behavior of the comma operator, is equivalent to
[NSString stringWithFormat:EXIFDictionary]
which is obviously wrong. Omit the parentheses, and it will be fine:
[NSString stringWithFormat:#"EXIF Properties: %#", EXIFDictionary]
You don't want those parentheses:
NSString *EXIFString = [NSString stringWithFormat:#"EXIF Properties: %#", EXIFDictionary];
Related
I get the dictionary from web service and this dictionary contain encoded key-value pair. I used some code for decode this key-value.
Code no. 1 :
[NSString stringWithUTF8String:[[dict valueForKey:#"desc"] cStringUsingEncoding:[NSString defaultCStringEncoding]]];
But when I run this code then it get crashed and got the error [NSString stringWithUTF8String:]: NULL cString'
When debugging it, dictionary contain keys & values also "desc" key having a value.
On other side i have one code that worked fine.
Code no. 2:
[NSString stringWithFormat:#"%#",[dict valueForKey:#"desc"]];
But almost everywhere in my app, I used code no.1 and its worked very well.
and now i have totally confuse i this error [NSString stringWithUTF8String:]: NULL cString' came while i check dictionary contain keys & values.
Why do you create a C-String from NSString and then (back) NSString from C-String?
Why not simply
NSString *desc = dict[#"desc"];
And – as always – do not use valueForKey unless you can explain why you explicitly need KVC.
I have what should be a dead-simple piece of code that is failing for me in strange ways.
void MediaShare(char* text, char* furl) {
NSString *status = [NSString stringWithUTF8String: text];
NSString *media = [NSString stringWithUTF8String: furl];
[[SocialShare sharedInstance] mediaShare:status media:media];
text is just a line of text for Twitter sharing, and furl is just a file location string. I am getting a crash down past this function that comes down to bad data getting passed. Putting a breakpoint at the head of this function yields the following-
Image of Xcode variable monitor
The two values look fine, although not sure if the * values that only contain the first char are a problem.
Anyway, jumping to the end, and status and media appear to be converted to hex values.
Converted to hex values?
Any ideas? To give the full story, this is a Unity plug-in. I am simply passing in two strings from Unity C# to this function.
Thanks so much.
The code looks fine so far, if the input values are well formed C char* strings that can be interpreted as an UTF-8 encoded string.
status and media being hex values at the end of the function hint that they are. Both are pointers to Objective-C objects, so this is expected. Print them to the debug console or use po status at the debug console to check their contents (it will print the result of the -description method of status which is the string content in that case).
The subsequent crash might be caused elsewhere in the code.
What's the crash's log output?
I would like to get a clarification/difference on the NSString declaration. Consider the following codes:
NSString *str = #"string";
NSString *str = [NSString stringWithFormat:#"string"];
NSString *str = [[NSString alloc] initWithString:#"string"];
Can anyone help me to understand the difference between the above three type of string declaration? Does the difference come in terms of memory or will there be any other reasons? I have gone through various posts to understand the difference, but I couldn't understand the exact difference.
Sree
Edit (thanks for the comments):
Using ARC, the first statement is used by the compiler to create a string that is accessible during the lifetime of the app and never deallocated.
The last two statements produce the same kind of string.
Using manual memory management, the second statement produces an autoreleased string.
The last produces a retained string. This means, when using the last statement, you would have to add a release later in the code.
for: NSString *str = #"string"; used when you use as a static string .
for Exmple.
int abc=5;
for: NSString *str = [NSString stringWithFormat:#"%d",abc]; used when you convert your integer or float into string.
for: NSString *str = [[NSString alloc] initWithString:#"string"]; used when above same same reason but only difference is you alloc string and then passes static string.
but in ARC no need to alloc string.
as I remember in this case
NSString *str = #"string";
the memory for the string will be allocated once and will be reused for all same strings in whole application. Something like global constant.
https://en.wikipedia.org/wiki/String_literal
There is the proof: "Objective-C string constant is created at compile time and exists throughout your program’s execution. The compiler makes such object constants unique on a per-module basis, and they’re never deallocated"
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Strings/Articles/CreatingStrings.html
The others 2 is the same, also you can formate string with stringWithFormat method: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Strings/Articles/FormatStrings.html#//apple_ref/doc/uid/20000943
NSString literal
#"string"
This will make the compiler emit a statically allocated NSString instance. The object itself will never be deallocated (release is a no-op).
Unique instance from format
[NSString stringWithFormat:#"string"]
Here the string is created from parsing and transforming the format string. This involves runtime overhead and returns an autoreleased instance.
Initialize by copying a literal
[[NSString alloc] initWithString:#"string"]
This will (1) create the literal, (2) allocate a default string, (3) throw away the default string, (4) call copy on the literal, and (5) return the result (again, the literal, because copy just returns it). The logic retain count is +1 (automatically handled by ARC).
This code works fine:
NSString *titleForMail =[NSString stringWithFormat:#"text %#",_infoTFProduct.text];
[mailCont setSubject:titleForMail];
While this code gives me the error above.
[mailCont setSubject:#"yo! %#", _infoTFProduct.text];
I'd love to know why.
Because, well, [mailCont setSubject:#"yo! %#", _infoTFProduct.text]; clearly has 2 arguments? In fact, the comma is what signifies the end of the first argument and the start of the second.
That syntax is not universal for interpolating strings. stringWithFormat: and NSLog I believe are the only cases that can handle this argument format.
So very few methods that accept strings will also accept strings with interpolation arguments. If you want to interpolate values into a string and use that anywhere you can use a string, you must use [NSString stringWithFormat:] first.
Try placing this where you need it.
[mailCont setSubject:[NSString stringWithFormat:#"yo! %#", _infoTFProduct.text]];
I have an NSURLRequest being made that to a server that returns a string.
string = [[NSMutableString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
receivedData is the mutable array that the downloaded data is stored in. Everything works fine.
I have now, however, added another value to that string. An example of the returned string would be 14587728000000 , 376.99. Originally it was one value so I didn't have to do any splicing. But, now that I have another value, I want to be able to separate it into two different strings.
What should I do to separate the two values into different string? Some kind of search that goes till the first space, or something like that. I have access to the server, and the string is generated in PHP so the separator can be anything.
You can do this with the NSString componentsSeparatedByString method:
NSString *string = #"14587728000000,376.99";
NSArray *chunks = [string componentsSeparatedByString: #","];
You can find some other common NSString tricks (where I found this one) here.
Use -(NSArray *)componentsSeparatedByString: and pass in the token to split by.