NSString category method not called after creating NSSavePanel - objective-c

I have a simple Cocoa application (39 KB zipped) that consists of an application delegate (AppDelegate) and an NSString category (and a default window that does nothing).
In its init method, the AppDelegate creates an NSSavePanel. Before and after it does this, it logs the length of a string trimmed of whitespace and newlines by an NSString category method: stringByTrimmingWhitespace.
The string consists of whitespace and newline characters. My category method should trim all of these characters, resulting in a 0-length string.
Before the NSSavePanel is created, my stringByTrimmingWhitespace method is called and returns a 0-length string, as expected. After the NSSavePanel is created, my stringByTrimmingWhitespace method does not appear to be called, and whatever method is called does not trim newlines. However, a different NSString category method that does exactly the same thing—stringByTrimmingWhitespaceAndNewlines—is called and works as expected.
I have absolutely no idea what is causing my stringByTrimmingWhitespace to not be called or how to fix it (besides renaming it, which is what I’ve done). I’m also concerned that other category methods on other classes may be getting trashed. Does anyone know what’s happening here?

It seems as though NSSavePanel is loading a category on NSString for its own use, with a method whose name conflicts with your -[NSString(TurnerAdditions) stringByTrimmingWhitespace] method. You can verify with this code:
NSString *foo = #"!";
NSLog(#"Responds to '-stringByTrimmingWhitespace': %#", [foo respondsToSelector:#selector(stringByTrimmingWhitespace)] ? #"YES" : #"NO");
NSSavePanel *panel = [NSSavePanel savePanel];
NSLog(#"Responds to '-stringByTrimmingWhitespace': %#", [foo respondsToSelector:#selector(stringByTrimmingWhitespace)] ? #"YES" : #"NO");
Why it doesn't behave the same as yours is somewhat strange (edit: no it's not, see #rdelmar's comment).
You should always be prefixing the method names in your categories, specifically for instances like this. Cocoa naming conventions are fairly explicit, which makes it very likely to have name conflicts. Because of the way categories are handled (e.g. they can be loaded in the middle of an app's execution without your knowledge) it's difficult/impossible for the compiler to provide conflict errors.

Related

Objective-c pointers magic. Type protection

I have a dictionary.
I extract one of its values as follows:
NSString *magicValue= [filterDict valueForKey:[filterDict allKeys][0]];
[SomeClass foo: magicValue];
And foo is:
- (void)foo:(NSString*)magicValue
{
NSLog("magicValue is string:%#",[magic isKindOfClass:[NSString class]] ? #"YES" : #"NO");
NSLog("magicValue is number:%#",[magic isKindOfClass:[NSNumber class]] ? #"YES" : #"NO");
}
If the dictionary value is number magicValue will be NSNumber. So the defined string pointer will be pointing to an NSNumber. The log will return yes for the number check.
I never added protection to such methods, to check what class "magicValue" is. I assumed that when I define a method with string parameter it will be string.
Should I start accounting for such behavior and always add checks, or is it the fault of the guy that assigned that dictionary value to magic in such a way and used my method. I need some best practices advice and how to handle this.
This question could have already been answered but I didn't know how to search for it.
Short answer: No, do not check that, if there is no special reason.
Long answer:
You have to differentiate between two cases:
A. Using id
You have a variable or a return vale of the type id. This is in your example -valueForKey:. The reason for that typing is to keep the method generic. Even it is theoretically possible, in practice a type mismatch in such situation is very rare and detected fast in development. With a different motivation I asked the audience (>200) in a public talk, how many times they had such a typing error in production. For all listeners, all of their apps in all of the app's versions there was 1(in words: one!) case. Simply forget about that risk. It is the anxiety of developers using statically typing languages (Java, C++, Swift).
B. Wrong assignment
If you do not have an id type, it is still possible to do such tricks. (And sometimes you want to do that. That is a strength of dynamic typing.) There are two subcategories:
You can do it implicitly:
NSString *string = [NSNumber numberWithInt:1];
The compiler will warn you about that. So everything is fine, because the developer will see his mistake. You do not have to protect him or your code.
One can do it explicitly:
NSString *string = (NSString*)[NSNumber numberWithInt:1];
In such a case, code can break. But he did it explicitly. If it is wrong, the developer had criminal energy to do so and you do not have to protect him from himself.
Most of the time you should know what class you're referencing, or at least what you intend it to be. On the occasions where you have an uexpected class which can cause a crash depending on what messages you send to it, you can then debug your code and get the correct reference.
There are times, usually when dealing with inheritance, when you need to determine the class at runtime rather than at compile time. This is when, isKindOfClass: can be useful. If you know that a value could be one of many classes, I would extract it as an id and then cast it at the last moment e.g.
id value = [[NSUserDefaults standardUserDefaults] valueForKey:aKey];
if ([value isKindOfClass:[MyClass class]]) {
// Do one thing
}
else {
// Do another
}

Xcode: #dynamic class variable not working

I have a class which declares a User and includes these variables:
(User.h file):
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * unid;
(User.m file):
#dynamic name;
#dynamic unid;
I have an array of values by parsing a string.
I then want to set the values accordingly:
(ViewController.m file):
[user setName:[returned objectAtIndex:1]];
[user setUnid:[returned objectAtIndex:2]];
When this is run the compiler gives me the following error:
unrecognized selector sent to instance
*** WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate: <NSInvalidArgumentException> -[User setName:]: unrecognized selector sent to instance
When I comment out the setName line it works fine.
I then looked at the classes of the two objects from the returned array and they were both: __NSCFString
I then tried this piece of code:
(ViewController.m file):
[user setName:[returned objectAtIndex:2]];
Again the same error.
Why would the same input fail in one case and succeed in another if they are both expecting the same input?
Thanks.
EDIT:
This error is weird as this part of the app does not interact with any webviews. This returned array is parsed from a string gather from a webpage:
(ViewController.m file):
NSString *string = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://url_goes_here.com" encoding:NSUTF8StringEncoding error:&error];
NSArray *returned = [returned componentsSeparatedByString:#"#"];
However the unid is also parsed from this array without any problem.
The #dynmaic keyword means that you'll be providing the accessors yourself. If you want the compiler to create accessors for you, simply delete the #dynamic name declaration. (Because #synthesize is now the default, you don't have to use it explicitly.) Otherwise, you'll need to create the -name, -setName:, -unid, and -setUnid: methods yourself.
it is actually a set up class by xcode using the NSManagedObject subclass for core data
This is an important detail. In the case of managed objects, Core Data will provide the accessors for you and you just need the #dynamic property declaration to let the compiler know that it shouldn't generate accessors itself.
I'm a little confused as to why this error is coming from a web view delegate method. It might help if you could explain a little more about how your Core Data classes are interacting with a web view.
why would this work for the unid, but not the name
The error you're getting is an run time error -- an exception is being thrown. It's likely that the name accessor is simply the first one to be used; the same thing might happen for unid if that property were to be set first.
This error is weird as this part of the app does not interact with any webviews.
Another important clue. At this point, it sounds very much like you've got a bad pointer. You're sending -setName: to an object that's not what you think it is, and in this case it turns out to be a web view delegate. Try turning on NSZombies to help you track this down.

Declaring and implementing a method that itself executes one line of code

I've many times seen a case where a programmer needs to assign some value (Object or primitive type, does not matter). And let's say this value is an NSString and can be obtained from the following expression
[myObject description]// returns NSString
But for some reason I've seen many people declare another method that itself returns an NSString and executes the above command only. Like:
-(NSString*)getDescription{
return [myObject description];
}
Is this just a matter of preference, or is is there some benefit from it?
Is this just a matter of preference, or is is there some benefit from it?
Those one line wrappers are often used to:
introduce behavior of a method that is meant to be overridden
or (more frequently) to simplify the program. If the method did not exist, you may find the complexity of the program grows. It serves to demonstrate intent, for clarity, documentation, and to minimize redundant implementations (simplifying the program).
There is definitely some "benefit" of creating a method or even better, overriding the "standard" NSObject description method..
If you have a custom NSObject for example and override the +(NSString *)description method you can then return information directly inside that object.
Take for example the following was overwritten in the NSObject we called foo.
+ (NSString *)description {
return #"Hello there";
}
Now, if you ever called [foo description] it would return the string "Hello there".
However, if you just returned description without overwriting the description method, it'd return something like <foo>0x12234 or something.
So yeah, it definitely has a lot of benefit to overriding a custom NSObject description.

Should I use an intermediate temp variable when appending to an NSString?

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.

Selectors in Objective-C?

First, I'm not sure I really understand what a selector is. From my understanding, it's the name of a method, and you can assign it to a class of type 'SEL' and then run methods such as respondToSelector to see if the receiver implements that method. Can someone offer up a better explanation?
Secondly, to this point, I have the following code:
NSString *thing = #"Hello, this is Craig";
SEL sel = #selector(lowercaseString:);
NSString *lower = (([thing respondsToSelector:sel]) ? #"YES" : #"NO");
NSLog (#"Responds to lowercaseString: %#", lower);
if ([thing respondsToSelector:sel]) //(lower == #"YES")
NSLog(#"lowercaseString is: %#", [thing lowercaseString]);
However, even though thing is clearly a kind of NSString, and should respond to lowercaseString, I cannot get the 'respondsToSelector' conditional to return "YES"...
You have to be very careful about the method names. In this case, the method name is just "lowercaseString", not "lowercaseString:" (note the absence of the colon). That's why you're getting NO returned, because NSString objects respond to the lowercaseString message but not the lowercaseString: message.
How do you know when to add a colon? You add a colon to the message name if you would add a colon when calling it, which happens if it takes one argument. If it takes zero arguments (as is the case with lowercaseString), then there is no colon. If it takes more than one argument, you have to add the extra argument names along with their colons, as in compare:options:range:locale:.
You can also look at the documentation and note the presence or absence of a trailing colon.
Selectors are an efficient way to reference methods directly in compiled code - the compiler is what actually assigns the value to a SEL.
Other have already covered the second part of your q, the ':' at the end matches a different signature than what you're looking for (in this case that signature doesn't exist).
That's because you want #selector(lowercaseString), not #selector(lowercaseString:). There's a subtle difference: the second one implies a parameter (note the colon at the end), but - [NSString lowercaseString] does not take a parameter.
In this case, the name of the selector is wrong. The colon here is part of the method signature; it means that the method takes one argument. I believe that you want
SEL sel = #selector(lowercaseString);
NSString's method is lowercaseString (0 arguments), not lowercaseString: (1 argument).
Don't think of the colon as part of the function name, think of it as a separator, if you don't have anything to separate (no value to go with the function) then you don't need it.
I'm not sure why but all this OO stuff seems to be foreign to Apple developers. I would strongly suggest grabbing Visual Studio Express and playing around with that too. Not because one is better than the other, just it's a good way to look at the design issues and ways of thinking.
Like
introspection = reflection
+ before functions/properties = static
- = instance level
It's always good to look at a problem in different ways and programming is the ultimate puzzle.
From my understanding of the Apple documentation, a selector represents the name of the method that you want to call. The nice thing about selectors is you can use them in cases where the exact method to be called varies. As a simple example, you can do something like:
SEL selec;
if (a == b) {
selec = #selector(method1)
}
else
{
selec = #selector(method2)
};
[self performSelector:selec];
As per apple docs:
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html
A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.
Example:
(lldb) breakpoint --set selector viewDidLoad
This will set a breakpoint on all viewDidLoad implementations in your app.
So selector is kind of a global identifier for a method.