Explain this obj-c method signature to me - objective-c

- (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.

Related

Possible implementations of editable UITableView data sources

I'm seeking to implement a UITableView that has sections representing the recent history and future queue of a media player. It seems to me that a Queue-type structure would be most applicable for this, as this represents the nature of the operation, but the requirement that the future queue part be editable poses some challenges.
I think that a linked list would be the best option here to store the media representations, as opposed to a vector type structure where all of the elements are stored contiguously. It seems to me that, in the case of moving or removing an object within the queue and adding object at the end, a linked list is more efficient than a vector, as simply assigning a few pointers different values seems more lightweight than moving entire chunks of memory. The internal implementation details of NSMutableArray seem quite obscure but I'm assuming it's a vector type.
However, I've never really seen a true linked-list implementation in Objective-C. Furthermore, the structure of UITableViewDataSource, requiring cellForRowAtIndexPath: to be called with a specific row rather than simply iterating through the list, exposes the weakness of linked list implementations, as seeking a specific index can be expensive. This would be irrelevant if cellForRowAtIndexPath: is only called in order, but it seems reckless to ignore the indexPath parameter in favor of just iterating through the list.
How are these structures typically implemented? Is iterating through a link list as proposed a bad idea?
Since Objective-C doesn't have an explicitly defined "linked list" object type, the closest alternative would be NSMutableArray.
You should never assume the order in which
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath;
will be called, and if you implement the UITableView correctly, it should only be called for the index paths of cells right before they appear on screen (thus the order it's called would alter based on the direction the user is scrolling in).
I recommend that you create a 2-dimensional NSMutableArray with the 1st representing the sections in the table and the 2nd representing the rows in each section. You would then initialize the array using something like:
self.sectionsArray = [NSMutableArray array];
[self.sectionsArray addObject:[NSMutableArray array]]; // history rows
[self.sectionsArray addObject:[NSMutableArray array]]; // queued rows
Which would allow you to easily retrieve the stored items using something along the lines of:
- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger section = indexPath.section;
NSUInteger row = indexPath.row;
id fetchedObject = self.sectionsArray[section][row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellReuseID"];
// perform setup here based on the fetchedObject
return cell;
}
I've listed some NSMutableArray methods you may find helpful below:
- (void)addObject:(ObjectType)anObject;
- (void)insertObject:(ObjectType)anObject atIndex:(NSUInteger)index;
- (void)removeObject:(ObjectType)anObject atIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(ObjectType)anObject;
- (void)removeLastObject;

Empty method name, what does this actually do?

I'm currently learning myself objective-c and iOS programming and found myself stuck with non-working code due to this subtle error for an hour.
Consider the following code:
#property (strong, nonatomic) NSString *name;
- (NSString *):name { return #"Some name"; }
At first glance (and for anyone new) this looks like an overridden getter for the name property. But theres a very subtle : that shouldn't be there. You get no warning/error from the compiler/parser/runtime here, so my question is what does this actually end up as?
I tried to figure a way of calling this method once I saw the error, but didn't succeed in my few attempts.
The method signature - (NSString *):name breaks down to the following:
- It is an instance method (versus a class method with a +).
(NSString *) It returns a string.
: If you were to speak the name of this method, it would simply be called "colon". : tells the compiler that your method accepts one parameter as well.
name There is a parameter called name.
When you don't specify a type, the compiler assumes you meant id, so this method actually fleshes out to be - (NSString *):(id)hello
A valid call to this method would be: [self :#"hello"].
You can do really weird things because : is a valid name for a method, and the compiler assumes id. You could, if you really wanted to, have a method called - :::. The compiler would assume you meant - (id):(id):(id):(id), a method that returns an object of type id and takes three parameters of type id. You'd call it like so: [self :#"hello" :anObject :myObject];
A method declare like the one you posted is rare (and poor style, imo). Objective-C is supposed to be verbose. Methods break down like this:
First character: Either - or +. - means it is an instance method, + means it is a class method.
Value in parentheses: The return type of the method. In your example, the method returns an (NSString *).
The rest (before the curly braces) is the method name along with any parameters they take. You could have a name with no parameters, in which case the method name would not have a : in it. Such as - (void) reload; This would be a method that doesn't return a value and takes no parameters.
If your method takes parameters, they will be mixed into the method name and usually will declare the type (unlike your example). Such as - (NSString *) reverseString:(NSString *) stringToReverse; In this example your method name would be reverseString: it takes one parameter, an NSString* that will be called stringToReverse in the method definition.
Usually, if you see a : with no type it will be a case like - (float) addThreeValues::: This method returns a float and takes 3 parameters. This would be an appropriate definition because the three values don't matter what order they are provided because we are just adding them.

Can someone explain function names in Objective-C? [duplicate]

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.

How do I read Objective C methods

I think the biggest problem I'm having with understanding programming is understanding what a particular method does. For example
- (BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
When I look at the above method I know that it returns a boolean and that the method receives the following.
NSTableView
NSTableColumn
NSInteger
However, I don't understand what I need to provide to use the method correctly.
Do I just return a boolean?
It comes down to a saying: code tells you how, comments tell you why.
If you are writing a method, you need to know why you want the method and document it accordingly, a.k.a. comments. If you are overriding a method, then you would hope the producer of the method would document about what the method does.
If you're diving into iPhone development without a bit of programming background, you should at least read up the Introduction to The Objective-C Programming Language. If you want to find out what a particular method does in your code, you can always right click the method name and choose "Find Text in Documentation" to read more about it.
This method will be called by the table (or something) on your delegate (the class you are implementing this method in) when the table needs to know if a certain row and column can be edited. You just need to return YES or NO to indicate if you want to let it be edited.
This is an example implementation:
-(BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
return NO;
}
This will mean the table can never be edited.
A more complex implementation like this would let only the first row be editable:
-(BOOL)tableView:(NSTableView *)aTableView shouldEditTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex {
if (rowIndex == 0)
return YES;
else
return NO;
//This can be shortened to:
//return rowIndex == 0;
}
The name of the method tableView:shouldEditTableColumn:row: should give you a clue that it is about editing rows and columns in a table view. You could probably guess that, since it is returning a boolean it's called to determine with a table view should edit the supplied row of the supplied column. However, that would just be a guess, so at this point (if I hadn't been using that method only yesterday and thus know exactly what it is for) I would start googling for it (or using Xcode search if I had access to Xcode).
A useful tip for Googling Cocoa documentation is to search only on site:developer.apple.com so we'll try site:developer.apple.com tableView:shouldEditTableColumn:row:. The top hit in this case is NSTableViewDelegate which is the one we want.

Populating NSTableview from a mutable array

I've been attempting this for two days, and constantly running into dead ends.
I've been through Aaron Hillegass's Cocoa Programming for MAC OS X, and done all the relevant exercises dealing with NSTableview and mutable arrays, and I have been attempting to modify them to suit my needs.
However none of them seem to be using an array with objects as a data source, it seems to use the tableview as the datasource.
I'm trying to implement Jonas Jongejan's "reworking" of my code here, with a Cocoa front end to display the results.
Any pointers or suggestions I know this should be simple, but I'm lost in the wilderness here.
I can populate the table by setting the array
It's pretty simple really, once you get to understand it (of course!). You can't use an NSArray directly as a table source. You need to either create a custom object that implements NSTableViewDataSource or implement that protocol in some existing class - usually a controller. If you use Xcode to create a standard document based application, the document controller class - (it will be called MyDocument) is a good class to use.
You need to implement at least these two methods:
– numberOfRowsInTableView:
– tableView:objectValueForTableColumn:row:
If you have a mutable array whose values you'd like to use in a table view with one column, something like the following should do as a start:
– numberOfRowsInTableView: (NSTableView*) aTableView
{
return [myMutableArray count];
}
– tableView: (NSTableView*) aTableView objectValueForTableColumn: (NSTableColumn *)aTableColum row: (NSInteger)rowIndex
{
return [myMutableArray objectAtIndex: rowIndex];
}
It has just occurred to me that you could add the above two methods as a category to NSArray replacing myMutableArray with self and then you can use an array as a data source.
Anyway, with a mutable array, it is important that any time you change it, you need to let the table view know it has been changed, so you need to send the table view -reloadData.
If your table view has more than one column and you want to populate it with properties of objects in your array, there's a trick you can do to make it easier for yourself. Let's say the objects in your array are instances of a class called Person with two methods defined:
-(NSString*) givenName;
-(NSString*) familyName;
and you want your table view to have a column for each of those, you can set the identifier property of each column to the name of the property in Person that that column displays and use something like the following:
– tableView: (NSTableView*) aTableView objectValueForTableColumn: (NSTableColumn *)aTableColum row: (NSInteger)rowIndex
{
Person* item = [myMutableArray objectAtIndex: rowIndex];
return [item valueForKey: [tableColumn identifier]];
}
If you replace valueForKey: with valueForKeyPath: and your Person class also has the following methods:
-(Person*) mother;
-(Person*) father;
-(NSString*) fullName; // concatenation of given name and family name
you can add table columns with identifiers like: father.fullName or mother.familyName and the values will be automatically populated.
You could go the datasource route and do all of the heavy lifting yourself, or you could let bindings do all the heavy lifting for you. Add an NSArrayController to the nib file that has the table view in it. Make sure that the File's Owner of the nib is set to the same class that has the mutable array in it. Bind the contentArray of the array controller to File's Owner.myMutableArray. For each column bind Value to the array controller arrangedObjects and add the appropriate key path. This will allow you to get things like user sorting for free if you ever need it.
On the iPhone (I know you're talking about Mac, but maybe this could help) you have to use delegation for loading a tableView. It asks for a cell and you use your array to fill-in the data where needed.
I'm not sure if this works for the Mac, but it'd be worth looking into.
Maybe set dataSource to self and use those delegate methods to access your array based on the row and column #
Apple has a whole guide for Table View Programming so I suggest you start with the Using a Table Data Source section of the that guide.