When I use XCode I (obviously) put a bunch of NSLog statements in to keep track of some variables and method executions, etc. However, I keep getting this warning:
Format String is not a string literal (potentially insecure). I understand why this is here, but I also understand that it bugs the living crap out of me, especially when I have 20 or 30 of these warnings making it harder to track down real errors. Especially because everything in the string is defined by the system, not the user. Is there some way that I can disable this warning? Here's an example of a line that causes the warning.
NSLog([#"writeInfo " stringByAppendingString:[self saveFilePath:temp]]);
NSLog takes in a format string on its own, you do not need to inline create strings. In other words, you only need to write:
NSLog(#"writeInfo %#", [self saveFilePath:temp]);
Related
I'd like to use memchr instead of strlen to find the length of a C string potentially used as the backing string of an NSString. Is this safe to do, or do I risk reading memory that I don't own, causing a crash? Let's assume that the NSString will not be released before I'm done with the internal buffer.
memchr(s, 0, XXX) and strlen(s) should pretty much behave identically, save for mechr()'s ability to terminate after XXX bytes. But strnlen() can do that, too.
And that behavior is probably exactly what you don't want.
Neither function accounts for any kind of unicode encoding. Thus, the returned length will be the length-in-bytes and not the # of characters.
Use -length on the NSString if you want the string length. Beyond that, what are you trying to do?
In Xcode, I'm getting the error "direct comparison of a string literal has undefined behavior," and I know why I'm getting it, but is there some way for me to click a button and have Xcode remove it? I'm saying this because in 370 places in my app I've gotten it.
The clang option to disable this warning is -Wno-objc-literal-compare.
However, warnings are there for a reason; this one is because comparing against NSString literals using == is not guaranteed to behave as you might expect. Use isEqual: or isEqualToString: instead and you can both get rid of this warning and avoid having this turn into a bug for you later.
You can avoid the warning using `isEqualToString` instead of `==`.
`==` simply compares the pointers, which will usually be different even
if their contents are the same. The`isEqualToString` method compares
their contents.
I'm currently running Mountain Lion OS X 10.8 with Xcode 4.4 installed. I'm running the iOS 5.1 simulator. I'm using Buzztouch as a learning tool while I'm studying Objective-C and Xcode. I get the following alerts when I compile, but the build succeeds. However, I would like to know exactly what is going on and how I can remedy the situation. Thank you for any assistance you can provide. Here's the code and the alerts I'm getting:
BT_fileManager.m
Data argument not used by format string
[BT_debugger showIt:self:[NSString stringWithFormat:#"readTextFileFromBundleWithEncoding ERROR using encoding NSUTF8StringEncoding, trying NSISOLatin1StringEncoding", #""]];
Data argument not used by format string
[BT_debugger showIt:self:[NSString stringWithFormat:#"readTextFileFromCacheWithEncoding ERROR using encoding NSUTF8StringEncoding, trying NSISOLatin1StringEncoding", #""]];
BT_camera_email.m
Semantic Issue
Sending 'BT_camera_email *' to parameter of incompatible type 'id'
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
NSLog(#"is camera ok");
UIActionSheet *photoSourceSheet = [[UIActionSheet alloc] initWithTitle:#"Select Image Source"
delegate:self
Again, thanks.
Greg
I have no idea what Buzztouch might be, however.... :-)
The first warning is fairly simple. In a format string there are placeholders beginning with a '%' sign to indicate where data values should be substituted. For example, to substitute a string, one would use '%#'. In the examples you show, there are no placeholders but there are data values -- empty strings. The compiler is warning that something you indicate you want to have put into the new string created by stringWithFormat: won't be.
To be sure about the second one, I'd want to see the .h file that declares BT_camera_email but my best guess is that it doesn't adopt the UIActionSheetDelegate protocol. The description of initWithTitle:... says the second parameter should be id<UIActionSheetDelegate> and that's probably what is being complained about.
This works -- it does compile -- but I just wanted to check if it would be considered good practice or something to be avoided?
NSString *fileName = #"image";
fileName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", fileName);
OUTPUT: TEST : image.png
Might be better written with a temporary variable:
NSString *fileName = #"image";
NSString *tempName;
tempName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", tempName);
just curious.
Internally, compilers will normally break your code up into a representation called "Single Static Assignment" where a given variable is only ever assigned one value and all statements are as simple as possible (compound elements are separated out into different lines). Your second example follows this approach.
Programmers do sometimes write like this. It is considered the clearest way of writing code since you can write all statements as basic tuples: A = B operator C. But it is normally considered too verbose for code that is "obvious", so it is an uncommon style (outside of situations where you're trying to make very cryptic code comprehensible).
Generally speaking, programmers will not be confused by your first example and it is considered acceptable where you don't need the original fileName again. However, many Obj-C programmers, encourage the following style:
NSString *fileName = [#"image" stringByAppendingString:#".png"];
NSLog(#"TEST : %#", fileName);
or even (depending on horizontal space on the line):
NSLog(#"TEST : %#", [#"image" stringByAppendingString:#".png"]);
i.e. if you only use a variable once, don't name it (just use it in place).
On a stylistic note though, if you were following the Single Static Assigment approach, you shouldn't use tempName as your variable name since it doesn't explain the role of the variable -- you'd instead use something like fileNameWithExtension. In a broader sense, I normally avoid using "temp" as a prefix since it is too easy to start naming everything "temp" (all local variables are temporary so it has little meaning).
The first line is declaring an NSString literal. It has storage that lasts the lifetime of the process, so doesn't need to be released.
The call to stringByAppendingString returns an autoreleased NSString. That should not be released either, but will last until it gets to the next autorelease pool drain.
So assigning the result of the the stringByAppendingString call back to the fileName pointer is perfectly fine in this case. In general, however, you should check what your object lifetimes are, and handle them accordingly (e.g. if fileName had been declared as a string that you own the memory to you would need to release it, so using a temp going to be necessary).
The other thing to check is if you're doing anything with fileName after this snippet - e.g. holding on to it in a instance variable - in which case your will need to retain it.
The difference is merely whether you still need the reference to the literal string or not. From the memory management POV and the object creational POV it really shouldn't matter. One thing to keep in mind though is that the second example makes it slightly easier when debugging. My preferred version would look like this:
NSString *fileName = #"image";
NSString *tempName = [fileName stringByAppendingString:#".png"];
NSLog(#"TEST : %#", tempName);
But in the end this is just a matter of preference.
I think you're right this is really down to preferred style.
Personally I like your first example, the codes not complicated and the first version is concise and easier on the eyes. Theres too much of the 'language' hiding what it's doing in the second example.
As noted memory management doesn't seem to be an issue in the examples.
I just converted an Objective-C library to a C library in the hopes of making it cross platform. However, everything appears to do okay until I send this thing off to be processed.
It's at the point I get an error.
Looking back a few revisions, I noticed something in the debugger.
Right after a malloc'd string like so:
char *theString = malloc(SOME_SIZE * sizeof(char));
I would see that theString is \x03 and *theString is "3 '\003'".
I assumed at first that this was just weird memory since I haven't don a strcat or anything to it, but that odd starting character(s) carry through, and recurs at every other point that I perform a similar malloc.
In terms of normal processing, this is fine. Unfortunately, I don't understand what it is, otherwise, I'd just do something drastic like cutting off that first character or something.
Can someone explain to me what that is and how I deal with it if I want to convert it to an NSString safely?
The value returned by malloc is not guaranteed to be set to any specific value. It's only guaranteed to point to memory you own of length at least as long as you specified. If you want the memory initalized to some value you'll need to do it yourself. Or alternately use calloc which will zero out the memory.