Method with multiple input parameters - objective-c

I understand how to create my own methods that accept input parameters in objective-c but I have never actually created a method with more than one input parameter!
From methods I have used with multiple input parameters each has a name along the lines of
first:second:third:
and look like
- (void)first:(NSString *)fname second:(NSString *)mname third:(NSString *)lname;
my question is when creating your own method with multiple input parameters do you have to create a name like first:second:third or can you just have something like C++ where you have the one name followed by a list of input parameter types followed by the parameter names... if I remember correctly.
fullName:(NSString, NSString, NSString) fname, mname, lname;

No. A method must have the format as you described:
- (void)first:(NSString *)fname second:(NSString *)mname third:(NSString *)lname;

You have to have the parameters interleaved with the method signature. It's ok because xcode has code completion and it can give you nice descriptive names about what your method is doing and what it requires.
e.g.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
In the example above without even looking at the API for UIViewController you can get a pretty good understanding of how this method works and what it's params are. It is good practice to name your methods well to describe what they do (it can remove the need for most commenting if done well).
You may well of course see a method written like this
- (void)myMethodThatAcceptsARectangle:(float)x :(float)y :(float)w :(float)h;
But this will not be very clear in use as to what the parameters relate to:
[self myMethodThatAcceptsARectangle:1.0f :1.0f :1.0f :1.0f];
So you should avoid this (I added it incase you ever see this and wonder what's happening).

fullName:(NSString, NSString, NSString) fname, mname, lname;
Yes, you can do something like that. It'd look like this instead:
-(void)fullName:(NSString*)fname :(NSString*)mname :(NSString*)lname
and you'd call it like this:
[foo fullName:first :middle :last];
That largely defeats the point of Objective-C's method names, though, and the main reason to do something like that is to register your dislike of the normal Objective-C convention, or perhaps to get yourself kicked off whatever project you're working on.

Another option could be variadic parameters. They're used to provide a variable amount of parameters, even though you wouldn't have a name on each one of them. e.g.
[NSString stringWithFormat:#"My name is %# %#", #"John", #"Doe"];
It would be something like this:
- (void)names:(NSString *)names, ...;
Implementation, additional info

Here's a simple example for Method with parameters.
- (void)methodName:(NSString *)parameterOne methodNameContinues:(NSString *)parameterTwo;
For Example,
-(void)showAlertMsg:(NSString *)message withTitle:(NSString *)title;
Here you can see, we've a prefix "withTitle" for the second parameter. We've to proceed the same for the other parameters too.

I can think of a perfectly good reason to use NSDictionary to pass arguments. I also believe it answers the question.
You can place all of the items in an NSDictionary then unpack them. This maybe useful if you have say a persitanceStore NSObject that you want to send a list of parameters to.

Related

Must Objective-C messages have split up names to have different arguments?

That's an example
- (NSArray *)shipsAtPoint:(CGPoint)bombLocation withDamage:(BOOL)damaged;
May we delete withDamage part here? What's the difference if that's available?
You actually can, and then you would call the method like this:
[obj shipsAtPoint:point :YES];
But it's considered bad style and virtually no one does this.

Sorting NSArray igonring Umlauts

I want to sort an array I have so that the Umlauts are treated as normal versions of the characters (ä == a, etc.). I thought localizedCaseInsensitiveCompare: should do the trick. But it doesn't. Anyone?
Best
–f
localizedCaseInsensitiveCompare: compares using the standard rules in the current language chosen by the user, ignoring the case. In your case you want to disregard the diacritics, not the case. This means you need to do something else.
You need to use compare:options: and pass NSDiacriticInsensitiveSearch as an option. see here.
To sort an array using it, you need to either use a block using sortedArrayUsingComparator:, or implement a category method in NSString and pass that selector to sortedArrayUsingSelector:. Don't forget to prefix the name of the category method so that it doesn't overlap with a private method in the framework. So, do something like
#interface NSString (myaddition)
-(NSComparisonResult)mySecretDiacriticsInsensitveCompare:(NSString*)string;
#end

Objective-C method signatures. Are they inconsistent?

I'm new to Objective-C, but please help me out here.
What I'm seeing is that method signatures in Objective-C that take multiple parameters seem inconsistent.
Example:
- (void) sendEmail: (NSString *) toStr
subject:(NSString *) subjectStr
body:(NSString *) bodyStr;
OK, so here we have 3 "parameters" (at least that's what I'm used to calling them), but 2 of them have "external" names (subject, body) but the first one doesn't! Isn't there something wrong with that from a consistency/style point of view?
When we call this method we do it like:
[emailObj sendEmail:#"test#test.com" subject:#"testSub" body:#"this is a test"]
(Hopefully I did that right, remember I'm new to this.)
So the subject and the body are clearly marked in the call, but not the "to" address? It seems really wacked to me. Why is that first parameter getting special treatment?
I guess you thought that in the method declaration
-(void) A:(NSObject*)a B:(NSObject*)b C:(NSObject*)c
A is the method name, B and C are the names of parameters.
In Objective-C, the totality A:B:C: is the method name (more technically, called the selector) and used as a unit when you call a method by name. For example,
if([obj respondsToSelector:#selector(A:B:C:)]){
...
}
checks if obj responds to A:B:C:. But [obj respondsToSelector:#selector(A:)] will be NO in this case.
So, you should really think of the totality of A:B:C: as the method name, and A is the name of the first parameter.
Note also that you can't call A:B:C: as A:C:B:, either.
In most cases, methods like this are normally named so that the lack of a name on the first parameter makes sense. In this case, I would expect something like sendEmailTo.
I would say that if you're confused about what a method does, then it's probably not named as well as it could've been.
Given the selector above, I would expect the 3 parameters to be some sort of email object, a subject, and a body. Since, however, the first parameter is not an "Email" object but rather the recipient of an email, I would probably rename this method to be:
- (void) sendEmailToRecipient:(NSString *)recipient subject:(NSString *)subject body:(NSString *)body;

Is there a reason why I sometimes read in Books "layoutSubviews Method" and sometimes "drawRect: Method"?

I am wondering why in Books and Apple Documentation sometimes a Method has that colon as suffix, but sometimes not. I guess it means that if it has no colon, it has no parameter. On the other side, if it has a colon, it has exactly one parameter. Right or wrong?
That's correct, though it is an easy typo to make. You should always check the documentation to ensure the signature of any method to avoid any runtime errors.
A method with signature:
- (void)refresh
Will be used like:
[myObject refresh];
A method with signature:
- (void)refreshView:(UIView *)view
Will be used like:
[myObject refreshView:view];
And finally, a method with signature:
- (void)refreshView:(UIView *)view updateLabels:(BOOL)update
Will be used like:
[myObject refreshView:view updateLabels:YES];
You're right that the trailing colon signifies a single parameter, and it's important to use the full including-colon name in code -- e.g. #selector(drawRect:)
However, while I can't find an example off hand, in prose, I believe you'll occasionally see methods written without the trailing colon just to make it read better. I know I do this when writing comments/documentation -- e.g. "Subclasses should customize the doFoo method" when I actually mean doFoo:. So, if you see method names in prose, it's probably a good idea to check in the header file or class reference documentation for the correct signature.
Objective-C refreshView: and refreshView are two different methods. The first takes one parameter, the other takes no paramaters. As you say.
This is important because that is the full name of the method, and you need to be able to write this correctly when passing selectors.
For example when showing a sheet:
- (void)beginSheet:(NSWindow *)sheet
modalForWindow:(NSWindow *)docWindow
modalDelegate:(id)modalDelegate
didEndSelector:(SEL)didEndSelector
contextInfo:(void *)contextInfo;
the didEndSelector is usually of the form:
- (void)sheetDidEnd:(NSWindow *)sheet
returnCode:(int)returnCode
contextInfo:(void *)contextInfo;
and so in the beginSheet method this will need to be passed to the didEndSelector parameter as:
#selector(sheetDidEnd:returnCode:contextInfo:);
Getting the signature of the selector wrong will lead to much late night head scratching while debugging.

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.