What's the difference between these Objective C method styles? - iphone

There seems to be two standard ways of writing methods in Objective C, and I can't quite grasp what the difference is and why one is used rather than the other. For example, from the UIWebViewDelegate:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
}
- (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
}
Why isn't the second one simply written as webViewDidFailLoadWithError, or why doesn't the first one match the second style?
Another example, this time from UITableViewDataSource:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 0;
}
How come numberOfSectionsInTableView doesn't follow the same format as the other methods?
I'm sorry if this is a very simple question - it's just been bugging me for a while now and I'd like to get it clear in my head!
Thanks in advance for your help.

It all comes down to the number of arguments. Pretty much every delegate method passes the sender of the method as its first argument. If the method does not need further arguments, the method signature is in the first style, otherwise it is in the second, following the Cocoa convention to name each argument.
Unfortunately, it is not possible to append more text to a method signature after the last argument. If it were, I am sure Apple would rather name the method - (void) webView:(UIWebView *)webView didFinishLoad.
Edit: There was an interesting discussion recently here on Stack Overflow on the history of this syntax decision: Why must the last part of an Objective-C method name take an argument (when there is more than one part)? where even Brad Cox, creator of Objective-C, chimed in.

You can have multiple web views or table views on the screen at the same time. During a callback of the methods you listed, you can take a look at the web views or table views' tag property to decide which web view or table view is responsible for such a call back.

It's part of Apple's own Objective-C coding guidelines regarding delegate methods:
http://akos.ma/gt
Delegate methods (or delegation methods) are those that an object invokes in its delegate (if the delegate implements them) when certain events occur. They have a distinctive form, which apply equally to methods invoked in an object’s data source:
Start the name by identifying the class of the object that’s sending the message:
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
So, to answer your question, all of the methods you quote follow the same pattern: the first (and sometimes the only) parameter of the method is the object calling the delegate method.

Why isn't the second one simply written as webViewDidFailLoadWithError...
Because then it would have to be:
- (void) webViewDidFailLoadWithError:(NSError *)error {
}
which lacks the first argument, so when the method is called on the delegate, you wouldn't know which webview returned the error.
...or why doesn't the first one match
the second style?
because then it would have to be
- (void)webView:(UIWebView *)webView DidFinishLoad {
}
which is not a valid method name, since the 'DidFinishLoad' part is not preceded by an argument --that is, you can't just add parts to a method name without matching them with an argument (with the only exception that of a method that receives no arguments at all).
I hope that makes it clear.

Related

Is it generally bad practice to have many "initWith" parameters?

Say for instance I have an implementation of a UIView. The UIView contains a two labels, an image and a frame.
My "init" method ends up looking like:
- (id)initWithFrameAndLabelArrayAndImage:(CGRect)frame:(NSArray *)labelArray:(UIImage *)image;
Is that considered bad practice? Is it better to have a simple "initWithFrame" method and have the other label and picture as #properties?
It's fine. Apple does it frequently. For example, look at NSString:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsstring_Class/Reference/NSString.html
– initWithBytes:length:encoding:
– initWithBytesNoCopy:length:encoding:freeWhenDone:
– initWithCharacters:length:
– initWithCharactersNoCopy:length:freeWhenDone:
– initWithString:
– initWithCString:encoding:
– initWithUTF8String:
– initWithFormat:
– initWithFormat:arguments:
– initWithFormat:locale:
– initWithFormat:locale:arguments:
– initWithData:encoding:
But, following those patterns, yours:
- (id)initWithFrameAndLabelArrayAndImage:(CGRect)frame:(NSArray *)labelArray:(UIImage*)image;
Should probably be:
- (id)initWithFrame:(CGRect)frame labels:(NSArray *)labelArray image:(UIImage *)image;
Now, having said that, I probably wouldn't pass an array of labels. I would pass the data and have the custom view take that data and create/layout the subviews. You're sort of exposing the internal views that compose your custom view in the public methods and you may want to change how you render and compose them in the future.
Another approach would be to use delegates to render the labels the labels would be rendered by calling the delegate for the data it needs - similar to a table view.
Although having multiple paramaters is fine, you really shouldn't have any parameters that are unnamed. In your case, to call your method it would look like this:
[[* alloc] initWithFrameAndLabelArrayAndImage:frame :array :image];
This is generally bad practice. I would rearrange your custom initializer to be more along the following lines:
- (id)initWithFrame:(CGRect)frame labelArray:(NSArray *)labelArray image:(UIImage *)image;
or even
- (id)initWithFrame:(CGRect)frame andLabels:(NSArray *)labels andImage:(UIImage *)image;
I think this is basically a matter of preference, but I personally like to create "convenience methods" whenever I find my parameter list running amok (ie, shorter-named messages that call the longer ones using default values). For instance...
-(id)initWithFrame:(CGRect) frame {
[self initWithFrame:frame andLabel:#"Default text"];
}
-(id)initWithFrame:(CGRect) frame andLabel: (NSString *) str {
...
}
...
-(id)initWithFrame:(CGRect) frame andLabel: (NSString *) str ... andMothersMaidenName:(id) etc { ... }
I do question why you would use "initWithFrameAndLabelArrayAndImage:" as your first parameter, though, rather than just initWithFrame: andLabel: andArray: andImage:. Adding all the parameters to the first parameter name (and then repeating them in the subsequent ones) just seems redundant to me.

Understanding the delegates in UITableView and UITableViewController

I am learning how to use the UITableView and UITableViewController in the iOS and I think I may have confused myself. I have created a simple TableView and I have 2 sections. Nothing complicated.
I have the following defined and it builds fine:
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
// Section is going to be either 0 or 1, high or low
if (section == 0) {
return 1;
}
else {
return 2;
}
}
However what I don't understand is the definitions of the methods. Both methods have to return an integer so I understand the starting (NSInteger). The numberOfRowsInSection starts with tableView:(UITableView *)tableView and I don't understand why?
I'm am new to programming the iOS so be gentle :-) All help greatly appreciated.
Mike
The method name is "tableView:numberOfRowsInSection:". The first argument is the instance if UITableView which is asking the data source for the number of rows in a particular section. This is a useful convention as you might have a single object act as the data source for many table views or want to update the table view in some way when a delegate method is called. By passing the calling object to the delegate you avoid needing to have the delegate maintain an additional reference to that object.
Take a look at the NSURLConnection delegate methods dealing with authentication for an example of where this is really necessary.
tableView:(UITableView *)tableView is helpful if you need to know which tableView sent that delegate method.
This is Apple's naming convention for delegate and data source methods. numberOfSectionsInTableView: has no arguments other than the table view, so that argument is added at the end. tableView:numberOfRowsInSection: takes another argument, the index of the section in question. Apple has decided that, when there are other arguments, the calling object should go first, and the arguments come after that.
Check out the UITableViewController Class Reference
- (NSInteger)tableView:(UITableView *)tableView
The first part, NSInteger lets you know that you need to return a number return 1;, the second part (UITableView *)tableView lets you know that you are dealing with the UITableView class.

Changing cell appearance when editing UITableView _without_ using custom cells?

If I am using a custom UITableViewCell I can use the following methods to change the cell's appearance when transitioning state:
- (void)willTransitionToState:(UITableViewCellStateMask)state
- (void)didTransitionToState:(UITableViewCellStateMask)state
Is there a way to achieve this if I'm not using a custom tableview cell?
Edit: Please see Daniel Hanly's comment. Categories may be selectively applied using #import. My apologies to anyone that may have been misled by this answer. Relevant sections will be redacted for future reference.
Okay, attempt number two. As far as I am aware, there is no other documented way to implement the functionality you require without subclassing UITableViewCell. It's worth noting that Apple's docs on UITableViewCell specifically mention that the state transition methods are meant to be implemented by subclasses. That having been said, If you absolutely need to implement them without a subclass, there are a couple of less conventional solutions. Each comes with its own issues, and it may end up being unfeasible for you to implement them, but it's an interesting question nonetheless.
Disclaimer
If you only want a sane and relatively simple explanation, then consider the answer to your question to be "no, there is no way to do what you want." I only present the options below with the assertion that they will work. In no way do I endorse actually using them. Consider this my penance for providing my first answer with such an obvious flaw.
Option One - Categories
It is possible to get the functionality you're looking for by overriding the methods you listed in a custom UITableViewCell category.
The problem is that this approach would be a pretty bad idea 99% of the time. Once you define the category on UITableViewCell, those methods would be defined for all UITableViewCell objects throughout the app. Unless you want the exact same state transition functionality for every single table cell in the app, this approach isn't very helpful.
Option Two - Runtime magic
You can use the low-level Objective-C runtime functions to change the implementation of any method on the fly. Unlike the categories option, this approach is flexible enough to redefine the intended behavior whenever you need to, instead of being a one-shot deal.
For example, if you're trying to manage state transitions from a UITableViewController, you could do this:
CustomTableViewController.m
#import <objc/runtime.h>
- (void) customStateWillChange:(UITableViewCellStateMask)state
{
//custom UITableViewCell code
}
- (void) viewDidAppear:(BOOL)animated
{
//Store the original implementation
Method originalStateWillChangeMethod = class_getInstanceMethod([UITableViewCell class], #selector(willTransitionToState:));
originalStateWillChangeImplementation = method_getImplementation(originalStateWillChangeMethod); //variable declared in header file as type IMP
//Get the new implementation
Method newStateWillChangeMethod = class_getInstanceMethod([self class], #selector(customStateWillChange:));
IMP newStateWillChangeImplementation = method_getImplementation(newStateWillChangeMethod);
//Replace implementation
method_setImplementation(originalStateWillChangeMethod, newStateWillChangeImplementation);
//the rest of your viewDidAppear code
[super viewDidAppear:animated];
}
- (void) viewDidDisappear:(BOOL)animated
{
//restore the original implementation
Method originalStateWillChangeMethod = class_getInstanceMethod([UITableViewCell class], #selector(willTransitionToState:));
method_setImplementation(originalStateWillChangeMethod, originalStateWillChangeImplementation);
//rest of viewDidDisappear code
[super viewDidDisappear:animated];
}
This code may not suit your exact purposes, but I think it provides a useful example.
It's incredibly ugly though because the customStateWillChange: method defined here is only intended to be run as a part of the UITableViewCell class, but in this example it will be compiled as though it were part of the CustomTableController class. Among other annoyances, you would have to eschew the property dot notation, ignore compiler warnings and give up most if not all compile-time checks for that method's body.
Option 3 - Category with runtime magic
Exactly what it sounds like. Define any custom state change methods you like within a category (or several categories) on UITableViewCell. Be sure that each one has a separate name - adding two categories that each have a method of the same name will result in undefined behavior. Also, each one needs to have the same return type and argument types as the method it is intended to replace.
Then the references to [self class] in the above code would be replaced with [UITableViewCell class], and the customStateWillChange: method would be moved to the custom category. While still ugly, you can at least rely on the compiler to interpret the method bodies properly.
Of course, messing with the runtime adds a whole lot of complexity to keep track of. It could work fine, but it's not good design, it would take serious effort to ensure it worked safely and correctly, and it would be likely to bring anguish and despair to anyone maintaining it.
References
The Objective-C Programming Language - Categories and Extensions
Objective-C Runtime Reference
Absolutely. The UITableViewDelegate protocol specifies a number of methods to manage state transitions for the table view's cells. Take a look at the UITableViewDelegate Class Reference, specifically the methods listed under the heading "Editing Table Rows".
Edit
Sorry, you're right. The UITableViewDelegate methods don't respond to direct changes to the cell's properties. I've found a way that does work, but I'm going to put it in a different answer to avoid confusion.

How do I call - (void) viewDidAppear:(BOOL)animated from another method?

It is possible to call one method from inside another. I've implemented this function
- (void)pickAndDecodeFromSource:(UIImagePickerControllerSourceType) sourceType
I want to call following method inside the above one.
- (void) viewDidAppear:(BOOL)animated
I think I understand what you're asking... the question is.. well not there. Nonetheless:
What I think you're asking: "How do I call viewDidAppear from within another method...?"
- (void)pickAndDecodeFromSource:(UIImagePickerControllerSourceType)sourceType
{
...
[myController viewDidAppear:YES]; //Simply call it on whatever instance of a controller you have
...
}
If the question was actually "How do I override viewDidAppear?" then this is it:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
//YOUR STUFF
//GOES HERE
}
You can always call the delegate methods directly:
[self viewDidAppear:YES]
Called from inside your method should work.
I'm not sure exactly what you mean, but from the nature of your question I am guessing you are new to Obj-C so I strongly suggest reading Introduction to The Objective-C Programming Language if you have not already. If you have, great! What you are looking for is most likely under Objects Classes and Messaging - Object Messaging - Message Syntax

Delegates, can't get my head around them

Hey, I'm looking for useful resources about Delegates. I understand that the delegate sits in the background and receives messages when certain things happen - e.g. a table cell is selected, or data from a connection over the web is retrieved.
What I'd like to know in particular is how to use delegates with multiple objects. As far as I know, specifying the same delegate for an object (e.g. table cell) would cause the same events to be called for both the cells at the same time. Is there anything equivalent to instantiating a delegate for a particular object?
Thanks in advance!
In Cocoa, objects almost always identify themselves when calling a delegate method. For example, UITableView passes itself as the first parameter of the delegate message when calling it:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
If you wanted the same delegate to handle multiple UITableViews, then you just need a some conditional on the tableView object passed to the method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView == self.myFirstTableView) {
// do stuff
} else if (tableView == self.mySecondtableView) {
// do other stuff
}
}
}
If you don't want to compare the object pointers directly, you can always use the tag property to uniquely identify your views.
Usually, if you have a delegate method that might have to receive messages from many different objects, you simply have the calling object pass itself to the delegate in the message (method call).
For example, if you wanted a delegate method to extract the text from a tableviewcell's label, the method definition would look something like:
-(void) extractTextFromLabelOfTableCell:(UITableViewCell *) theCallingCell{
...
NSString *extractedText=theCallingCell.textLabel.text;
}
You would call the method from a tableviewcell thusly:
[delegate extractTextFromLabelOfTableCell:self];
Each instance of the tableviewcell would send itself to the delegate and the delegate would extract that instance's text. In this way, a single delegate object could handle an arbitrarily large number of cells.
A delegate is a way of adding behaviors to a class without subclassing or for attaching a controller to a class.
In the table view example you gave, the delegate is extending or controlling the table, not the cell. The table is designed to have a controller, the cell is not. This design choice is why you can't specify cell-specific delegates.
However, delegate methods will always announce the source object (the one to which the delegate is attached) and relevant parameters (like the cell involved) so you should always be able to handle the action fully.
In your case, if you have a cell and you would like the cell to manage itself, then the delegate method (which will probably be implemented on your UITableViewController) can simply fetch the cell from the source table using its NSIndexPath (passed as a parameter to the delegate method) and invoke a method on the cell subclass to do its work.
I always liked Chris Sells' ".NET Delegates: A Bedtime Story"