Is there design pattern for showing same view controller in several places with some customization? - objective-c

Very frequently we reuse same view controllers when developing universal apps both for iPhone and iPad. But frequently some customization is needed, like:
IF iPad THEN
...
ELSE
...
So, in order to achieve such customization the controller might have some property that is set during initialization of the controller, or there might be custom constructors. Just curious is there design pattern that suites for such situations.

Don't.... :) Use a common class called for instance MyClass and then sub-class it MyClass-iPad & MyClass-iPhone and use two different XIB for each. Avoid using this kind of stuff (there is no need for it).
Explanation:
The iPad version should only be aware of classes of the type Something-iPad this makes the code clean and creates a well defined architecture. If I jump into your code and someone tell's me: "Ok Jacky Boy, you have to make changes on the iPad version". I won't care to look ath the Something-iPhone classes. Most of the logic (business) should be on super class Something where the small tweaks should be on the sub-classes.
On side note, on most of my projects, normally I don't have anything on the Something-iPhone classes, because the design is done on the XIB. On the Something-iPad I would normally keep a reference to a UIPopOverController (just an example) and some rotations tweaks.
Edit 1:
I would receive an NSDictionary on the init of the UIViewController, like this:
initWithNibName:bundle:configurationDictionary:
After receiving this configurationDictionary, I would then use it on the viewDidLoad (for example). You could then do some cool stuff like this:
- (void)viewDidLoad
{
[[self view] setBackgroundColor:[[self configurationDictionary] objectForKey:BACKGROUND_COLOR_KEY]];
}

If you have different initializers or larger chunks of different functionality then it makes sense to define a base class with the core functionality and then an iPad-specific subclass and an iPhone-specific subclass.
But in cases where you only have a trivial difference (for example, displaying an action sheet), then I would simply use something like:
- (void)someMethod {
// a bunch of stuff that is the same
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// one or two lines for iPad
} else {
// one or two lines for iPhone
}
}
I have plenty of situations where I do both - subclass for the bigger differences and use UI_USER_INTERFACE_IDIOM for trivial differences in the base class.

If you need the same VC in N places but each time initialized a little differently I would move the logic in a specific factory class / category on the VC
like its done with for example SLRequest objects / in ShareKit

Related

Create single .xib for Universal app in Interface Builder? (iOS)

Apologies if this is a silly question, but I've done some googling and searched SO and haven't found anyone asking this exact question.
I have been doing iOS development for some time now, but I am completely new to the Interface Builder. What I want to know is this: is there any way to just create ONE .xib file and then use it for both iPhone and iPad in a Universal application?
It seems silly to me to have to create them separately; why do twice the work laying something out more than once in Interface Builder when I could do it once (with minor adjustments for screen size) in code?
Please let me know if I'm missing/misunderstanding something here. Like I said, I'm a complete Interface Builder newbie :)
EDIT: I have submitted non-interface-builder games to the App Store in the past where the iPhone and iPad versions were identical, so I'm not concerned with making the game look/feel different on each device. I intend for them to look exactly the same, aside from some slight positioning changes due to the difference in aspect ratio.
If you know what the resulting view would look like, based on autoresizing, you can indeed use only one .xib. May come in handy if the view is just some sort of a shared component that autoresizes as you want it to. However, if you need the view to look way different on iPad than on iPhone, just use two .xibs. It’s possible then to load the appropriate one as needed, for example in instance initializer, like this controller’s -init:
- (id)init
{
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
{
self = [super initWithNibName:#"YourNibForPad" bundle:nil];
}
else
{
self = [super initWithNibName:#"YourNibForPhone" bundle:nil];
}
if (self) { /* initialize other ivars */ }
return self;
}
The main reason that XIBs are separate files is because Apple feel that UIs designed for iPhones/iPod touches and iPads should be tailored to each respectively. This is echoed in their their iOS App Programming Guide, which says the following:
For views, the main modification is to redesign your view layouts to support the larger screen. Simply scaling existing views may work but often does not yield the best results. Your new interface should make use of the available space and take advantage of new interface elements where appropriate. Doing so is more likely to result in an interface that feels more natural to the user—and not just an iPhone app on a larger screen.
Whilst it can take time to maintain two XIBs for what is effectively one UI, I feel it is more straightforward than using one XIB and then having to connect up most of your UI elements in order to move them around programmatically when that XIB loads. After all, with two XIBs at least you can see what each UI looks like, and then make visual changes easily.
As an aside, don't forget iOS 5's Storyboards (read about them here), which make managing a view/view controller hierarchy much simpler.
Try to name them
MyCell.xib and MyCell ~ ipad.xib
then:
[self.tableView registerNib: #"MyCell" forCellReuseIdentifier: #"MyUniqueIdentifier"];
If your using IB, you need to create 2 separate xib files for iPhone and iPad. You need a separate iPad xib to make your app comply with the Apple iPad UI guidelines.

Best location for data and logic for possibly shared iPhone/iPad app

I'm coding my first app in XCode 4.2 supporting iOS 4.x through the current releases. To support iOS 4.0, I'm not using Storyboard feature and also using unsafe_unretained for weak references. I have AppDelegate files (.h and .m) along with several view controllers with UITabBarController. In my first view controller, in the -viewDidLoad method, I initialize two NSDictionaries and also start a timer with 1 sec interval. In the selector method, I have to pickup a random number between 0 and 7 to pick a corresponding value in both the dictionaries. The dictionaries are used only in the first view controller and not anywhere.
My first question is
where do I load those two dictionaries - in the AppDelegate -didFinishLaunchingWithOptions: method or in the first view controller's -viewDidLoad method?
I also wanted to support iPad. If that's the case, do I create a common class library to support iPhone/iPod/iPad?. If that is the recommended way, can I move the common functionality to the AppDelegate .m file instead?
Please advise.
You can move your common data and business logic into a separate set of model classes outside of the UI layers and appdelegates. This is one of the main benefits of the MVC pattern - by separating and making a clear distinction, it's easy to have separate view layers (one for phone and one for iPad).
That means all the data (dictionaries), logic with your random numbers and timers would be encapsulated and shared. That also allows you to cleanly unit test the majority model and logic programmatically. It also means you can make substantial changes to your algorithms and minimize the code churn.
When the timer goes off it can either post a notification or you can have a delegate pattern where it does a call back.
Related Post: Delegates vs. events in Cocoa Touch
If you do a shared model, one option is to use a singleton pattern where you access the model like:
[MyModel sharedInstance];
You should keep your code and data together if possible, which means that if you only access the dictionaries in your view controller then you should initialize them in the view controller's viewDidLoad.
I recommend keeping stuff out of the app delegate if possible or else you'll end up with a weird monster class that does too much stuff for which it shouldn't be responsible. If necessary, create one or more classes that manage common data (for example using the singleton pattern).
Whether you can/should use a common file for both iPhone and iPad depends on a number of factors. The main factor is: how different are the UIs? If they are very similar then use one class for both. You can also create a base class with common functionality and sub classes for iPhone and iPad which implement the necessary differences.

When do I need to subclass UIViewController and when can I just instantiate it?

I am learning iOS programming through the Big Nerd Ranch guide by Hillegass and Conway. I’m writing an app of my own as I go through the book, and one of the questions that has been bugging me is exactly when I need to subclass UIViewController (and its ilk) and when I can just instantiate it.
For example, my app consists of generic building blocks: the interface is tabbed, and the tabs lead to a UITableView, a UINavigationController that creates UITableViews, and so on. Following the book’s instructions, I have subclassed UITableViewController to create the table views. However, in creating the UITabBarController that contains all of my app’s content, it seems sufficient to instantiate a UITabBarController and then add a bunch of views to it. (All of this is done in the application:didFinishLaunchingWithOptions: method of my app delegate. Since most of my app consists of simple combinations of basic UI parts, I’m trying to do build the UI programmatically whenever possible.)
I get the impression that what I should be doing is creating a subclass of UIViewController (or UITableViewController or whatever) for every interface in my project. This seems weird to me, since most of these classes would only ever be instantiated once. Am I just misunderstanding how OO should be used in this case? (I have a good amount of programming experience but relatively little has been with OOP.) Should I be creating a subclass for each and every screen that the user will see?
Should I be creating a subclass for each and every screen that the user will see?
If each view requires different logic, yes.
Don't shy away from creating new classes for conceptually separate things. Programmers coming from non-OOP to OOP might feel that a file with only a small amount of code is a waste. Suppress this feeling. Classes are cheap, and help enormously to organise your thinking.
So you have two types of UIViewControllers in iOS. "Container" viewControllers and "Content" viewcontrollers. Both are subclasses of UIViewController but have very different purposes.
The Container type is what the UINavigationController and UITabController are. They are rarely subclassed and typically used as is (in fact, I believe Apple doesn't allow the subclassing of UINavigationController at all). These "Containers" take care of moving "Content" view controller around for you. They do not have much content of their own, beyond adding things like a tab bar or a navigation bar.
The "Content" view controller are the ones you create most of the time. You will rarely be able to use a UIViewController as is, because it will not have any functionality. That is why you subclass them. These are meant to represent a single "screenful" of content. So in effect, every "screen" the user sees should be controlled by a UIViewController subclass.
The UITableViewController is simply a specialized sublass of UIViewController that already contains some methods for managing tables.
The way the UIKit framework was designed was for you to use subclasses of UIViewController to display content and to use out-of-the-box "Container" controllers to facilitate the management of your UIViewController subclasses.
You need a subclass of UIViewController if you want to do any of the following (not an exhaustive list, but some examples)
customize the view hierarchy when the view hierarchy is loaded (in
viewDidLoad)
provide some behaviour as the view controller's views become visible
(or not) (in viewWillAppear:, viewDidAppear:, viewWillDisappear:,
etc.)
clean up after yourself as needed in viewDidUnload
create outlets to views in the hierarchy so you can adjust them as
needed in the above lifecycle methods
My reasoning behind subclassing UIViewController, and other classes is that:
Almost always you must initialize variables and assign values to the instances of classes. You add subviews and set their frames, define actions for the UIViewController instance, etc. If this UIViewController instance is directly from the base class, its initialization should be done outside of it. If this initialization is required at different places for multiple times, you may have to deal with repeated initialization process.
So, you've compiled these processes into a method, making it reusable from wherever this UIViewController instance is used. But where do you want to put it? Don't you think it's much better to put it inside the subclass of UIViewController? Also, you don't even have to come up with specific name for this initialization method. Just override the default -(id)init from the super class.
Though you may think it's suffice to use UIViewController without subclassing it for now, as your project grows, it will be challenged to deal with reusability issues. Take some time to look at your codes. Check if there is too much repetition for such as initializing an object, or assigning values to it. If you are doing same things with an instance of a class in multiple places, compile them into a method to be reused. And as number of such methods grow, you will find the need to use subclass which will contain these relevant methods for the instance.
No matter the size of your project, using classes to distinguish different objects is important. Almost always, the basic essential classification is done by the framework, making it unnecessary to introduce new concept for a class. However, this doesn't mean the framework also knows how your project and its objects can be classified into. By using subclass, you can utilize every benefit the development framework can provide and still keeping the objects in your project to be as unique as possible, based on the purpose you've designed for them.
Well about the UITabBarController you are right. There is no reason for you to subclass anything if the default behavior is sufficient. However once you need to do some custom things you will need to subclass it..
Also, why are you trying to build the GUI programmatically? For the learning curve? There is no real reason not to use InterfaceBuilder, it saves you a lot of time.
You should subclass the UITableViewController in order to get your data in the view, that is how the MVC model works. The default implementation does not offer anything in order to get your data in the view, I don't think they will ever do that in order to make sure that nothing is wasted, their 'connection' to the model object might be different from the one you want and you would end up writing an adapter if your model object is not compatible.
I hope this will help you out a bit.
And merry x-mas.

Specific Question About Proper Design

Now, I know this question is very opinion oriented because people generally design their apps differently... However, I want to know if I'm doing something incorrectly, or generally frowned upon in the objective c programming community, or if you have any suggestions as to how an experienced obj c developer might design this differently...
LOCATION is a struct and BULLET is an enum defined in a Constants.h header file, BulletV is a subclass of UIView, and Bullet is a subclass of NSObject
I have the following code:
#import "Bullet.h"
#implementation Bullet
#synthesize Type;
#synthesize Location;
#synthesize Strength;
- (id)initWithLocation:(LOCATION)location Type:(BULLET)type Strength:(int)strength
{
self = [super init];
if (self)
{
self.Location = location;
self.Type = type;
self.Strength = strength;
}
return self;
}
#end
#implementation BulletV
#synthesize Type;
- (id)initWithLocation:(LOCATION)location Type:(BULLET)type
{
self = [super initWithFrame:CGRectMake(location.x - 10.0, location.y - 2.0, 20.0, 40.0)];
if (self)
{
self.center = CGPointMake(location.x, location.y);
self.Type = type;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
switch (self.Type)
{
case Normal:
self.backgroundColor = [UIColor redColor];
break;
default:
break;
}
}
#end
Now, I am relatively new to MVC.. but it seems like keeping the model and the view separate creates a whole lot of duplications, which i hate in my code..
For example, the fact that we have 2 of the same named Properties (Location and Type) utilized in these implementation blocks kind of bothers me, but I don't know how I would do this any other way while still maintaining separation between the model and view.
Also, both init methods for the view and model are very similar, with the exception that the model also includes a strength parameter..
I have a very java-oriented mindset when programming, I like to have individual files for each object, and for each object to have a state and certain actions.. Now, this new design disallows for any actions to be utilized in these headers, because they need to be placed in a controller.
Any comments are welcome, if this is the way you would make a "bullet object" (more like just a rectangle) in your app, then feel free to comment so, but it just doesn't seem right to me. Feel free to give your insights.
I immediately see a couple of things I would change.
First naming conventions. Properties and instance variables usually start with a lowercase character while classes start with an upper case character. Class names should be descriptive so BulletV would be clearer as BulletView, "BulletV" might be a "BulletView", a "BulletVelocity", or who knows what else.
Secondly I would not allow a view to be responsible for it's own position. A view should be responsible for it's contents but not need to be aware of it's position in or anything else about its superview.
Instead I would consider what sort of object contains bullets with positions; a room, a level, or whatever. Let a view for that space position the views for whatever bullets it contains. An individual BulletView only need to decide how to draw itself based on the type of its bullet. Which, as Jano suggested, probably means you want to pass a bullet to the view's designated initializer.
Once you have that separation of responsibilities it hopefully makes sense for whatever object models the space containing bullets to manage their positions and possibly other behaviors like creating and destroying bullets.
If you were going to reuse OrangeView you would name it FruitView to start with, and pass a Fruit object superclass which would have a method fruit.color instead using a switch.
But I see what you are doing, color is a visual property, and MVC dogma demands that you keep each part isolated, so you smuggle Bullet in little pieces. This is not very object oriented, or any easier to understand or test. A benefit of OOP is thinking in objects, if you were to show your code to yourself, you would understand it better passing a Bullet object.
edit
All problems in computer science can be solved by another level of indirection except for the problem of too many layers of indirection. In a small app is very common for C to know M and V, and for V to know M. In java server side you create a bean just to feed the view, but that's uncalled for in such a small example. Even when you can spot the pattern before opening the class, it's more effort, more classes, more indirection. Not always a good fit for every application.
Apple talks about it in Cocoa Core Competencies and Cocoa Fundamentals Guide.
One can merge the MVC roles played by
an object, making an object, for
example, fulfill both the controller
and view roles—in which case, it would
be called a view controller. In the
same way, you can also have
model-controller objects. For some
applications, combining roles like
this is an acceptable design.

Objective C protocol as an equal to Java Interface?

The question is not only regarding the headline, but more of a "how will I achieve this, without trying to force a Java/Flash design into an Objective C (iPhone)program".
I have 6 views that extends UIView, these views all have different behavior but share certain methods, like -(void) update and -(void) changeState:(NSInteger)state.
A viewController, whose job is it to update, instantiate and display these views has a switch block to do this. So switch(4) {...} instantiates UIView4, but as I need a reference to the currently instantiated view (to do update and changeState:), I have a UIView property on my ViewController called self.currentView. As the instantiated UIView4 extends UIView I can easily go [self.currentView addSubview:UIView4instance] and then release the UIView4instance.
Now how will I call the [UIView4instance update] method on the view? or the [UIView5instance changeState] etc. etc.
Since I added it to self.currentView which is of type UIView it no longer has any reason to believe it has an update or changeState: method, meaning I cannot iterate the views and send them these messages.
This approach brings on a ton of other problems, I would need to test and typeCast my views each time I needed to do any operations on them.
If I were doing something like this Composite Pattern approach in, say, Java. I would either write an interface that all the views (UIView1, UIview2.... UIViewN) would implement. Or maybe an abstract class that all the views inherited the changeState: and update methods from.
This way I could have self.currentView just know that I'm adding objects to your view and they all conform to these methods.
The two solutions I can think of, with my very small Objective-C experience is:
doing it with delegation or categories, but this seems overkill in every way :/
I guess I could also extend UIView and then extend my class extending UIView again, but there is probably a reason Objective-C does not directly support abstract classes...
Hope someone could point me in the right direction regarding these issues.
Thanks:)
Yes it is equal. You can declare a protocol
#protocol MyViewProtocol
-(void)update;
-(void)changeState:(NSInteger)state;
#end
and declare your subclasses like
#interface MyUIView3 : UIView<MyViewProtocol> {
....
}
....
#end
Then, the declaration
UIView<MyViewProtocol>* view=[[MyUIView3 alloc] init];
means that view is an instance (of a subclass of) UIView which also conforms to MyViewProtocol.
Just the way it works in Java, I think. See the apple doc on protocols.
One thing to be aware of is that while defining a protocol like this is a convenience and certainly makes things clearer, it is by no means necessary to make your solution work. Objective-C binds methods at runtime, and so all you really need to do is to make sure all your view classes implement the methods you care about and call them.
You will get a complier warning for this, but it will work.
Now, in general it's probably preferable to define a protocol like this and it's what I generally do. But it's also important to remember that runtime binding is there and can be incredibly powerful.