When should I use a UIViewController in IOS Programming? - objective-c

I've been looking at the API for IOS Programming, and have been reading about view controllers and UIViews. It looks like UIViewController subclasses are really useful for Modal navigation and custom animation, but I can't see any other uses than that.
What is the benefit to using a UIViewController subclasses rather than a normal NSObject subclass?
Why
#interface MyViewController : UIViewController {
}
-(void)handleEvent;
#end
Instead of just
#interface MyViewController : NSObject {
UIView* view;
}
#property(retain) UIView* view;
-(void)handleEvent;
#end
Don't you just end up adding just the view to the window, not the actual viewController itself?
For most purposes, isnt all of the functionality you need encapsulated within the UIView object?
You just end up adding it like this:
[window addSubview:myViewControllerInstance.view]
Is there a use for UIViewController other than built in functionality like Modal Navigation?
Thanks.
(Sorry if this is a stupid question, I've been learning this for 2 days now)

Cocoa on Mac OS and iOS make heavy use of the Model-View-Controller (MVC) pattern. Following the MVC model, UIViewController is a Controller class. Its job is to coordinate interactions between your user interface (View objects) and your application data (Model objects). More basically, the Controller is primarily where you place your application's logic. It handles events and calls upon the view and model accordingly.
See the UIViewController reference, which has a nice overview on the class.
By deriving from UIViewController, you get a bunch of Controller functionality for free, such as loading views from a Nib file (initWithNibName:bundle:) and responding to view-related events (viewWillAppear:, viewWillDisappear:). Additionally, UIViewController is itself a subclass of UIResponder, which contains functionality for handling touch events (touchesBegan:withEvent, touchesMoved:withEvent, touchesEnded:withEvent).
Basically, there's no reason NOT to use UIViewController with all the functionality it provides. Even if you could manage to to do so, it would be way more work, for no real benefit.

Take a look at the properties and instance methods of the UIViewController Class, which you would not get for free if you just subclassed NSObject. There is a lot of stuff in there that you will use in all of your applications.

Related

Mock UIView in UIViewController

Consider an example when I'm having UIViewController with simple interface:
#interface MainViewController : UIViewController
#end
When it receives viewDidLoad or viewDidAppear messages it creates and places additional views.
When unit testing it, I want to mock up these views, so I need to change interface to this:
#interface MainViewController : UIViewController
#property (nonatomic) UIView *additionalView1
#property (nonatomic) UIView *additionalView2
#end
By doing this I'm moving responsibility of creating additional views to calling side, which, in my opinion, breaks encapsulation.
How can I avoid exposing so much of controller internals?
To support setter injection, you really have to expose it.
There are ways of trying to hide it, or mark it as off-limits. You can wrap the property declarations in #if DEBUG. Or you can move them to a class extension in MainViewController_Private.
But I find that these tricks only make the code noisier. So my approach is to go ahead and expose them. As I point out on Testability, Information Hiding, and the Class Trying to Get Out, such exposure can be a clue that a class may need to be extracted, or responsibilities shifted. For example, since you want to inject these views, should MainViewController really create them? Maybe the tension is leading us to make a factory, keeping MainViewController ignorant of the details of these views.

IOS - The correct way for using #import classes

I am writing a test project to learn to write everything in code. I want to do this way so that I can better understand what the Elements in Storyboard do for me behind the scene's
In my project I have several UIViewControllers which share the same UI elements. For Example I have a UITool bar at the top of the screen with several buttons in it.
Now I want to put that UIToolbar in a separate class so that I do not have to write it all out or copy n paste it in every controller.
Now I know I can achieve this by doing this:
#import "General_Add_ons.h" //the UIToolbar is properly set up in this file
#interface FirstViewController : General_Add_ons
and then I just use [self topToolBar]; //topToolBar is the name of the toolbar
Now I just want to clarify is this the best and or only way to this?
Somehow I feel I should be able to do this:
General_Add_ons *gao = [[General_Add_ons alloc] init];
[gao topToolbar];
Am I thinking about this the wrong way? The first way seems to be limiting in case I have multiple external classes.
Thanks in advance.
Your approach seem correct. If you have several UIViewController instances that need the same UI elements or other controller code, you can put those elements in a UIViewController subclass. In your case, I believe the class General_Add_ons is the UIViewController from which your subclasses will inherit.
This class (your General_add_ons) should have a property for the reusable toolbar, e.g.
#property (nonatomic, strong) UIToolbar *toolbar;
As an aside, class names in Cocoa, by convention are: prefix+capitalized words without underscores. Apple has a great reference on naming conventions.
EDIT
For clarification, you can subclass your custom subclass as many times as you need. For example in my code, I have a class CCFViewController that encapsulates common properties and behaviors that I want all of my view controllers to have. In the project, then, all of the view controllers inherit from that parent controller. Similarly, your toolbar will live in the superclass and the other controllers inherit from it.
I am not 100% sure but i think you should try it this way:
General_Add_ons *gao = [[General_Add_ons alloc] init];
[gao.topToolbar anypossiblemethodcall];

Interaction between Subview and UIViewController with Delegates

I've read a lot of articles to get some information about the whole delegate concept in objective c. At least I think I got the general idea of that. But I didn't found an answer for my question - or I just found it but didn't got it...
In my case I got a custom subview I'm adding programmatically on my UIViewController. I want to have an interaction from the custom UIView to call some methods of the controller. I think it would be better to have a delegate concept instead of making a reference to my UIViewController in the SubView, right?
My question is, isn't it possible to do something with my UIScrollViewDelegate. My UIViewController is implementing some delegate methods because my SubView is a UIScrollView. So would it be possible to add a custom method which I can call with something like:
[self.delegate myCustomMethodOnUIViewController]
Or what would be the best way? Should I set up a protocol and add it as custom delegate to my UIViewController? Do I have to set up then a delegate property on my subview?
Thanks for help!
Andy
If you're adding the UIView as a subview to the UIViewController and you want to execute some methods from the superview in your subview there may be some mistake in your software design.
If there's a necessity to do it, then use the #class variable for circular inclusions and call your methods. To read more about #class directive.
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocDefiningClasses.html
More illustration can be read at the link:
#class vs. #import
You can make it work with delegates and protocols, but make sure you handle memory properly within the same contexts to avoid leaks.

Common base class/code for UIView and UIImageView - alternative to multiple inheritance in objective-c

I have some functionality that I need in all my classes which derive from either UIView or UIImageView.
More specifically, I have gesture related code that both these classes need.
Currently my implementation is:
UIGestureView : UIView
UIGestureImageView : UIImageView
and make all classes derive from these.
These classes will again contain methods that the derived class will implement.
My problem is that the gesture handling code is duplicated in UIGestureView and in UIGestureImageView.
The natural thing here (as a c++ programmer) would be to use multiple inheritance
UIGestureView : UIView, GestureHandler
UIGestureImageView : UIImageView, GestureHandler
and let GestureHandler perform all the generic work but as far as I have understood this is not possible.
What is the objective-c way of doing this (without too many levels of child calling parent etc.)?
Just to stress, the problem is how to avoid implementing the same code twice, once in UIView (or its derived class) and again for UIImageView (or its derived class).
You could extend UIView with your gesture handling, and then every objects that inherits from UIView will have the methods you want. Not quite as awesome and subclassing, but would work on the global scope.
#interface UIView (GestureHandling)
- (void)didMoveAFinger:(UITouch*)touchOrWhatever;
// etc., etc.
#end
I have had similar issues with UIViewController and UITableViewController. I have a subclass of one that I want to share code with the subclass of the other. Yet there is no common place to inject that code if you want a subclass. The alternative is categories on the common superclass.
Check out categories: http://macdevelopertips.com/objective-c/objective-c-categories.html
You should try using protocols and delegation. They solve the multiple inheritance problem in objective-c.
#protocol MyProtocol <NSObject>
//Method declarations go here
#end
#protocol MyProtocol2 <NSObject>
//Method declarations go here
#end
#interface CustomView : UIView <MyProtocol, MyProtocol2>

Events for custom UIView

What's the best way for registering events for my UIView subclass, so that I can connect them to IBAction-s in interface builder?
Currently I've just got a standard UIView dropped onto my main view and I've set the class to "RadioDial" (my custom class). This displays the view fine, but I have no idea how to get events out of it.
Thanks
Please clarify: do you mean that you would like Interface Builder to offer your view controllers to wire up custom events that your view subclass will be emitting (much like the Button controls allow you to wire up Touch Inside, etc)?
If you need this type of functionality, you will need to use a generalized 'delegate' property on your View combined with a protocol.
#protocol RadioDialDelegate
-(void)dialValueChanged:(id)sender
#end
#interface RadioDial
{
id<RadioDialDelegate> radioDelegate;
}
#property (nonatomic, assign) IBOutlet id<RadioDialDelegate> radioDelegate;
This will allow the controller to wire up to the view (assuming it implements RadioDialDelegate) and receive any events that come out of the view. Alternatively, you can use an untyped delegate and in your View code, use a late bound call:
if([radioDelegate respondsToSelector:#selector(dialValueChanged:)]) {
[radioDelegate dialValueChanged:self];
}
Create a method in your view controller (if nothing else, you should have a RootViewController in you project). Let's say your method is
-(void) buttonClicked { code code code }
In the controller's header file (for example RootViewController.h) you then put:
-(IBAction) buttonClicked;
And in IB you right-click your button/radio dial/whatever. You will see a list of events and you can drag FROM the connector of the event you want your controller to receive, to the object in IB that represents the controler (probably First Responder). This depends on how your IB structure is set up, but it should be straightforward.
Another alternative is to learn how to create UIViews programatically, and forget about IB for the time being. Opinions are divided about whether it's better to learn to use IB at the outset, or whether it's better to learn how to do everything in code and save IB for later. In any case, it's necessary to learn both ways of setting up an interface at some point.