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

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.

Related

What are alternatives to "delegates" for passing data between controllers?

Are there alternatives to "delegates" to pass back data from one controller to another?
Just seems like a lot of work implementing a delegate just to pass back the result from a child controller, back to the parent controller. Is there not another method? Are "blocks" one answer, and if so some example code would be great.
Delegates aren't a lot of work, aren't a lot of code, and are commonly the most appropriate solution. In my opinion they're neither difficult nor messy.
Five lines of code in the child's interface. Before #interface:
#protocol MyUsefulDelegate <NSObject>
- (void)infoReturned:(id)objectReturned;
#end
Inside #interface:
id <MyUsefulDelegate> muDelegate;
After #inteface's #end:
#property (assign) id <MyUsefulDelegate> muDelegate;
One line of code in the child's implementation:
[[self muDelegate] infoReturned:yourReturnObject];
One addition to an existing line of code in the parent's interface:
#interface YourParentViewController : UIViewController <MyUsefulDelegate>
Three lines of code in the parent's implementation. Somewhere before you call the child:
[childVC setMuDelegate:self];
Anywhere in the implementation:
- (void)infoReturned:(id)objectReturned {
// Do something with the returned value here
}
A total of nine lines of code, one of which is merely an addition to an existing line of code and one of which is a closing curly brace.
It's not as simple as a returning a value from a local method, say, but once you're used to the pattern it's super straightforward, and it has the power of allowing you do do all kinds of more complex stuff.
You could use many ways:
Calling a method of the super controller, needs casting maybe
Notifications
Simple Key-Value-Observing
Core Data
Example for for 1.
interface of your MainViewController: add a public method for the data to be passed
- (void)newDataArrivedWithString:(NSString *)aString;
MainViewController showing ChildController
- (void)showChildController
{
ChildController *childController = [[ChildController alloc] init];
childController.mainViewController = self;
[self presentModalViewController:childController animated:YES];
[childController release];
}
Child Controller header / interface: add a property for the mainViewController
#class MainViewController;
#interface ChildController : UIViewController {
MainViewController *mainViewController;
}
#property (nonatomic, retain) MainViewController *mainViewController;
Child Controller passing data to the MainViewController
- (void)passDataToMainViewController
{
NSString * someDataToPass = #"foo!";
[self.mainViewController newDataArrivedWithString:someDataToPass];
}
KVO or notifications are the way to go in many cases, but delegation gives a very good foundation to build upon. If you plan on extending the relationship between the view controllers in the future, consider using delegation.
Blocks are not really relevant to the above, but in short - it is a technique introduced with iOS 4, where you pass around blocks of code as variables/ parameters. It is very powerful and has many uses. For example, here is how you enumerate objects in an array using a block:
[someArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
NSLog(#"obj descriptions is - %#", [obj description]);
}];
The part from the ^ until the } is a block. Note that I've passed it in as parameter. Now, this block of code will be executed for every object in the array (i.e. output will be the description of each object).
Blocks are also very efficient performance-wise, and are used heavily in many new frameworks.
Apple's blocks beginners guide is quite good.
Check out NSNotificationCenter — NSNotificationCenter Class Reference
Folks pay a lot of attention the the V and the C in MVC, but often forget the M. If you've got a data model, you can pass it from one controller to the next. When one controller makes changes to the data stored in the model, all the other controllers that share the same model will automatically get the changes.
You might find using a singleton is practical. Just use it as a central storage for all your shared data.
Then throw in saving the state of your application too;)

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

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.

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.

Effective way to design and manage iPhone application similar to settings

I would just like to clarify that by 'design', I mean software design, not UI design.
I have an application similar to the native settings app. The problem I have with it is it doesn't follow the same clear-cut MVC style. Other apps tend to focus around displaying one kind of thing. In the case of a periodic table app for example, it's elements. The elements clearly comprise the model, and they share similar properties and behaviours, meaning they can be displayed and interacted with identically. An app like this almost designs itself!
My app, like the settings apps, consists of an arbitrary selection of rows displaying dissimilar data in dissimilar ways. One row might contain a switch, the other might modally present a very specific view when tapped. They're all very different.
How do you design something like this?
At the moment, I'm doing it all in the view controller, and the relevant rows are being tracked via an enum:
enum {
kNameRow,
kGenderRow,
kJobTypeRow,
kLevelOfExerciseRow,
kEmailAddressRow,
kTelephoneNumberRow
};
As I described, these cells are all very different, so displaying cells is handled like this:
// - tableView:cellForRowAtIndexPath pseudocode.
switch (indexPath.row) {
case kNameRow: // create name cell.
case kGenderRow: // create gender cell.
case kJobTypeRow: // create job type cell.
case kLevelOfExerciseRow: // create level of exercise cell.
case kEmailAddressRow: // create email address cell.
case kTelephoneNumberRow: // create telephone number cell.
}
And interacting with cells is handled similarly:
// - tableView:didSelectRowAtIndexPath pseudocode.
switch (indexPath.row) {
case kNameRow: // do name-specific stuff.
case kGenderRow: // do gender-specific stuff.
case kJobTypeRow: // do job type-specific stuff.
case kLevelOfExerciseRow: // do level of exercise-specific stuff.
case kEmailAddressRow: // do email address-specific stuff.
case kTelephoneNumberRow: // do telephone number-specific stuff.
}
This seems hugely unwieldy, and has the added of problem of not working when the table is broken down into multiple sections.
Is there a better way to do this? Are there any design patterns I would benefit from using when working with big tables of largely unrelated data?
Any tips at all are hugely appreciated.
I've become fond of implementing section controllers that pull the logic out of you UITableViewController subclass (or other hosting controller) and move them into self-contained classes.
I ended up implementing a base protocol that defines what a section controller needs to do - for me, that includes the number of rows in a section and a cell for the row (don't need the whole index path since the controller deals with a single section). I've got optional method for returning a section name and row height. That's all I've implemented so far since that's all I've actually needed.
It works for me because my individual sections tend to be homogeneous, but you could easily use the idea to return heterogeneous cells within the same section or refactor the idea to have cell type controllers instead of section controllers. In the end, my UITableViewDelegate and UITableViewDataSource methods just need to figure out which section controller to call instead of embedded all the logic within the UITableViewController subclass.
I think I got the idea from this article, but I also saw a more recent article that describes the same idea.
you might want to look at coreyfloyds project http://github.com/coreyfloyd/Generic-Heterogeneous-Table-Views i think this might have the functionality you need.
Here's my suggestion - handle each cell as a member of the view.
lol, it's been a while since I've used a table, so I could just be talkin' crap here but give it a try.
instead of an enum use:
NSThingyCell *nameRow;
NSThingyCell *genderRow;
#property IBOutlet NSThingyCell *nameRow;
#property IBOutlet NSThingyCell *genderRow;
- (IBAction) nameRowChanged:(id)sender;
- (IBAction) genderRowChanged:(id)sender;
and then instead of a table call with a switch, just wire each individual cell up in Interface Builder.
This has the added benefit of being row-independent, so if you have to put "ageRow" in between name and gender, nothing gets screwed up.
This will also get pretty big, so if your view has several tables, you may want to consider splitting those tables out into separate nibs/controllers and loading the views at run-time.
Have you ever thought of simply having an array of objects for a class which contains a UI element and some other identifiable data?
#interface settingsOption {
NSString *key;
UIView *displayElement;
}
+ (settingsOption *)optionWithKey:(NSString *)key andDisplayElement:(UIView *)displayElement;
#property (nonatomic, retain) UIView *displayElement;
#property (nonatomic, retain) NSString *key;
#end
Where the class method would look like
+ (settingsOption *)optionWithKey:(NSString *)key andDisplayElement:(UIView *)displayElement;
settingsOption *option = [[settingsOption alloc] init];
option.key = key;
option.displayElement = displayElement;
return [option autorelease];
}
Your settings class would have an array of settingsOption instances.
- (void)somewhereInMySettingsClass
mySettings = [[NSMutableArray alloc] init];
[mySettings addObject:[settingsOption optionWithKey:#"age" andDisplayElement:[UIButton buttonWithStyle:UIButtonStyleRect]]];
[mySettings addObject:...];
}
The table's cellForRowAtIndexPath would just do
[cell addSubview:[[mySettings objectAtIndex:indexPath.row] displayElement]];
You were talking about sections, though, which would add another layer to the data. This might simply be a matter of splitting mySettings into an array of arrays instead, where each array in the array is one section.
Not sure if I missed anything above. Feel free to point and poke.
You might simplify the settingsOption class further by adding more helper classes for various types of elements, e.g.
+ (settingsOption *)buttonWithKey:(NSString *)key;
+ (settingsOption *)switchWithKey:(NSString *)key;
+ (settingsOption *)pickerWithKey:(NSString *)key withDataSource:(id <UIPickerViewDataSource>)source withDelegate:(id <UIPickerViewDelegate>)delegate;
etc etc.

Call back style

I am writing an iPhone application which in numerous places needs to perform non HTTP or FTP networking of a very simple request response type.
I've wrapped all this up into a SimpleQuery class that integrates with the run loop.
SimpleQuery *lookup = [[SimpleQuery alloc] init];
[lookup setDelegate:self];
[lookup doQueryToHost:queryServer port:queryPort query:queryString ];
As you can see the calling object sets itself as a delegate. When the results are complete it then calls a method on the delegate with the results.
[delegate simpleQueryResult:resultString simpleQuery:self];
I am now in a position where I have a user of SimpleQuery that has two types of query so I need to extend SimpleQuery to support this.
I can think of two sensible ways of doing this.
Firstly passing a selector into doQueryString, or a seperate doQueryStringWithSelector.
[lookup doQueryToHost:queryServer port:queryPort query:queryString selector:#SEL ];
Secondly passing a tag into doQueryString so that when the delegate is called it can query the tag, as the simpleQuery is passed, to find out what the results are for.
[lookup doQueryToHost:queryServer port:queryPort query:queryString withTag:tag ];
I'm just wondering which is best from a coding style perspective, the first seems simpler but tagging seems more in keeping with the iPhone SDK and Interface Builder
An option which is used commonly in Apple's code (for example, in UIControl) is to provide both a target object and a selector. This works only if there is a single callback, and is more appropriate than a delegate in that case. (If there are multiple callbacks, then you'll probably have to go with a delegate and the tag approach.)
If you go this route, then you do away with the delegate altogether and instead have a method with a signature like this:
doQueryToHost:(id)queryServer port:(int)queryPort query:(NSString*)queryString target:(id)target action:(SEL)action
Note that "action" is typically preferred over "selector" in methods arguments in this case. The query would simply call the selector on the target when done. This would allow your clients to have multiple selectors, and also multiple target objects; this can help clean up code because you don't need to shove everything into a single delegate object.
If you want to go with your tag route, you should call it "context", which is what Apple uses (for example, in addObserver:forKeyPath:options:context).
There's a third option that's a common pattern in the kits, which is to use #protocols.
For example:
#protocol QueryCompleteHandlerProtocol
- (void)queryType1Complete:(int)intStuff;
- (void)queryType2Complete:(float)floatStuff;
#end
What this does is declare a set of method calls that an object adopting the protocol has to conform to (the compiler will actually enforce this).
So your SimpleQuery object will hold on to something like the delegate pointer, which you might declare like this among the ivars:
NSObject<QueryCompleteHandlerProtocol> *callback;
What this tells the compiler is that callback is an object that descends from NSObject and adopts the QueryCompleteHandlerProtocol protocol. Sometimes you see this written as:
id<QueryCompleteHandlerProtocol> callback;
When you want to call the callback there's nothing special about them, SimpleQuery's methods will just call:
[callback queryType1Complete:1];
[callback queryType2Complete:2.0];
Finally you client for the procotol class will declare itself as adopting the protocol:
#interface MyClass : NSObject<QueryCompleteHandlerProtocol>
...
#end
And will set itself as the callback with some code like:
[lookup setCallback:self];
This is where the compiler checks that MyClass conforms to QueryCompleteHandlerProtocol, meaning it has implemented queryType1Complete: and queryType2Complete:.
I'm not sure I understand the problem here. Can't SimpleQuery's user just set another delegate object for the second query, or branch on the simpleQuery: parameter? That's a basic part of the delegate pattern, just like having two UIActionSheets for one view controller.