This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Method Syntax in Objective C
So I totally get the more common functions like:
-(void)viewDidUnload{
self.controllers = nil;
[super viewDidUnload];
}
However coming from a different programming background, I sometimes struggle with something like:
-(NSInteger) tableView: (UITableView *)tableView
numberOfRowsInSection:(NSInteger)section{
return [self.controllers count];
}
So I know the function returns a NSInteger. However I do get a little confused in how to mentally organize the rest of the function name ETC. I need to be able to visualize some structure. Like in this case is the function name numberOfRowsInSection with the parameter called section?
Help in this matter would be appreciated.
You can think of it like other programming languages by looking at
[object action:var withFoo:baz]
as
object."action:withFoo:"(var, baz)
Everything before colons is part of the method name, and everything after is arguments, so the name of the method is interleaved with the arguments passed to the method.
Yes, the way that Objective-C mixes arguments with parts of the method name seems weird at first. Everyone goes through a short adjustment period in this respect. But give it time -- after a little while, you may not want to ever see a comma-separated, parenthesized list of nameless parameters ever again.
In C++, you'd say something like:
Color *color = new Color(0.5, 0.7, 0.2, 0.8);
You know what those values mean, right? There's four of them, so obviously the parameters are in red, green, blue, alpha order. Or was it alpha, red, green, blue? Of course, it could also be hue, saturation, value, alpha... well, it doesn't really matter because you can always just look it up.
In Objective-C, you say:
UIColor *color = [[UIColor alloc] initWithRed:0.5 green:0.7 blue:0.2 alpha:0.8];
Isn't that better? You'll definitely still need to consult the documentation from time to time to remind yourself exactly what a method does, or what methods a class makes available. But you won't often find yourself consulting the docs just to figure out which parameter goes where.
Objective C has a descriptive way of writing methods..
-(NSInteger) tableView: (UITableView *)tableView numberOfRowsInSection:(NSInteger)section{}
It is a methods tableView, returning an NSInteger , takes two argument - a UITableView reference and an integer section. Now consider numberofRowsInSection as a description of what the argument is all about.Look at this example
-(NSInteger) calculateSum:(NSInteger)operand1 secondOperand:(NSInteger)operand2 andThirdOperand:(NSInteger)operand3{}
and I can call this methods as
[self calculateSum:var1 secondOperand:var2 andThirdOperand:var3];
Here "secondOperand" and "andThirdOperand" are not essential, I can write the above method as
-(NSInteger) calculateSum:(NSInteger)operand1 :(NSInteger)operand2 :(NSInteger)operand3{}
and call this method as
[self calculateSum:var1 :var2 :var3];
But first one is easy to read, if you tell what each variable is ..Hope this helps
Also see I used the word method instead of functions which is normally the objective c way..
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
This is a method that accepts 2 arguments, a UITableView and an NSInteger. It's notated like this: -tableView:numberOfRowsInSection:.
Yep that's basically it. In obj-C the full method names include the arg names. I believe that convention originated from Smalltalk.
Related
I am still learning Objective-C but I like to know the "why" behind everything I learn.
I would like to know why an Objective-C method requires that the types are enclosed in parentheses, such as:
- (IBAction) myAction: (UIButton *) sender;
Instead of:
- IBAction myAction: UIButton *sender;
I've tried finding answers and thought about it quite a bit but can't seem to see what the reasoning is for.
What troubles me is sometimes I actually forget that the asterisk (*) needs to be inside the parentheses, sometimes I accidentally type the following incorrect signature:
- (IBAction) myAction: (UIButton) *sender;
As to me, this more logically represents the argument is a pointer, not the type.
That's C casting syntax:
int foo = (int)bar;
Think of it as casting the parameters and return value to specific types.
In the very early days of Objective-C return values and parameters defaulted to the id type. So you'd see method declarations like this:
-myAction:sender;
For numerous reasons it became preferable to strongly type the return value and parameters in Objective-C code, to the point that all return values and parameters are strongly typed, even if they're id:
- (IBAction)myAction:(id)sender;
The asterisk is also C syntax. UIButton* is a specific type, different from UIButton and UIButton**. You could do this:
typedef UIButton* UIButtonRef;
and then use UIButtonRef instead of UIButton*:
- (IBAction)myAction:(UIButtonRef)sender;
i'm trying to understand this in objective-c :
in this example, indexPath is a pointer but we use it "as is" in the function : indexPath.section, instead of (for example) *indexPath.section(with a *) :
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
return (indexPath.section == 0) ? nil : indexPath;
}
so, in objective-c, we don't need to add a * to get the content of the variable where the pointer points to...?
but i found this function, where they use a * on the pointer inside the function (on reverse ) :
NSInteger lastNameFirstNameSort(id person1, id person2, void *reverse)
{
NSString *name1 = [person1 valueForKey:LAST];
//...
if (*(BOOL *)reverse == YES) {
return 0 - comparison;
}
and for the id variables, they are using the variable name as is : for example here : person1
So, could someone explain me the differences between those 2 examples :
why on the first example, we don't add a * on indexPath,
why we don't add this * on the id variables, and we use it with *reverse in the second example?
Thanks
You are confusing dot-notation with reading a structure. This is not surprising, since Apple made them ambiguous.
indexPath.section does not mean "the section structure element in indexPath. It doesn't even mean "the property section in indexPath." It means [indexPath section]. It just calls the method section and returns the result.
Similarly, foo.bar = baz does not literally mean "set the property bar to baz." It literally means [foo setBar:baz]. Whatever setBar: does will be done. In most cases, it sets an ivar.
Since indexPath is also technically a struct pointer, it is possible in some cases (but not always, and not often if you code correctly) to say indexPath->section. You should never do this. (There are some extremely rare exceptions, but you are unlikely to encounter them.)
The frustrating thing about all of this is that foo.bar might be a structure reference or it might be a method call. Without knowing what foo is, you can't know. This is one of the problems with dot notation.
If you find it confusing, don't use dot notation (it continues to be a controversial feature among experienced developers). It is never required. It's just a shortcut for the more explicit [foo bar] and [foo setBar:baz].
*(BOOL *)result means "cast result from void* to BOOL * and then dereference it as a BOOL. It's unrelated to dot notation.
Dot-syntax on ObjC objects (pointers to objects) is a way of accessing methods of the forms [object getter] and [object setter: value], using java/c#/javascript like notation (object.property) While the syntax isn't exactly consistent, object->property is already taken by direct property access. reverse is just a normal void pointer, and so the (BOOL*) converts it to a BOOL pointer, and the * before it dereferences it. id types are still pointers, it's just that the syntax for property access in ObjC isn't consistent with the existing C syntax.
- (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) section
I'm pretty comfortable with obj-c, but I don't understand this method signature. Specifically why this method has all that extra stuff before the method name, and what it means. Like I get that the - is an instance method, and that the return type is NSInteger
but why is tableView: (UITableView *) tableView in front of the method name?
WHy do some instance methods for the UITableViewDataSource protocol have nothing infront of the name? numberOfSectionsInTableViewis defined differently.
Can someone explain it to me?
Lets break it down into parts:
-
This means it's an instance method. The alternative is + which means class method.
(NSInteger)
This is the return type of the method. In this case it's NSInteger.
tableView:
The first component of the selector name (which is, in full, tableView:numberOfRowsInSection:). The : indicates that a parameter follows.
(UITableView *)
The type of the parameter.
tableView
The name of the parameter. This is largely irrelevant in the method signature (except as a hint to the reader as to the purpose), but in the implementation this is the variable that is bound to that parameter.
numberOfRowsInSection:
The next component of the selector name.
(NSInteger)
The type of the second parameter.
section
The name of the second parameter.
Note, the only required space in this entire line is the one between tableView and numberOfRowsInSection:. All other spaces can be elided to produce
-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
Though the most common format you'll find looks like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Edit: Looks like there's still some confusion about the latter part of the question. The tableView: component of the selector is there to provide the UITableView* instance that's asking the question. All of the methods in the UITableViewDataSource protocol provide the sending tableview as an argument. Some of these methods have other arguments, and some don't. The ones that have additional arguments are all formatted as tableView:someOtherThing: (e.g. tableView:numberOfRowsInSection:), but this isn't required. It could be called numberOfRowsInTableView:forSection:, or numberOfRowsInSection:ofTableView:, or even foo:bar:, but it's a stylistic choice that was made by the API developer to preserve a consistent naming scheme that assist both the developer and the person reading the code later. As for the methods that don't take any other parameters, they look like numberOfSectionsInTableView: because that's just a natural name for the method. They can't be called tableView:numberOfSections because that's an illegal selector (all components after the first must have a parameter associated, and therefore must have a trailing :).
In each case a reference to the tableView that is asking for data or calling a delegate method is given to the user
// |
// V
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
// |
// V
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
That way if you have one datasource/delegate object that is in charge of multiple UITableView's you can distinguished between which one is asking for data/ is calling a method.
This is a pretty common pattern.
If you are using a UITableViewController the likelihood is that you will ignore the tableView parameter anyway as you are normally only dealing with the one UITableView
The reason for the ordering of the params e.g. tableView being at the beginning is probably preference and it reads better when there are multiple parameters, however when you only have the tableView paramater is must be the last.
I'm an Objective-C newbie and am enjoying reading/learning Objective-C in order to do iPhone development but I'm struggling to understand some of the code, especially the code that comes with the UIKit framework.
For example, take this line:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSelection:(NSInteger)section {
...
I understand the parameters passed in but am struggling to understand the return parameter. Any help appreciated.
For this particular method, the return type is NSInteger; it is located at the beginning of the method's declaration. See the Objective-C Programming Guide for details on how to declare methods.
The value returned is the number of rows for the given section in a grouped UITableView.
In a more C-like pseudo code this could be rewritten as:
NSInteger returnNumberOfRowsInTableViewSelection(UITableView* tableView, NSInteger section)
{
...
}
Contrast with a similar function using simple types:
int add(int a, int b)
NSInteger is the return type, tableView and section are the parameters. You may find the named parameter syntax in ObjC longwinded and confusing at first but in my opinion it leads to much more readable and maintainable code :)
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.