Should UIViews have properties? - ios

Using proper MCV with Objective-C can a UIView subclass have #propertys?
i.e. in the .h file
#class MyViewSubclass;
#interface MyViewSubclass : UIView
#property (strong, nonatomic) UILabel *labelLabel;
#property (strong, nonatomic) UILabel *valueLabel;
#end
or should this be done in a UIViewController subclass?
Thanks in advance.

It is most common to subclass UIViewController to manage the labels, fields, images, and other views within a view hierarchy. However, if you are creating a reusable component view that will be used throughout your application, then it's perfectly appropriate to subclass UIView and add properties to your subclass.
From Apple's iOS App Programming Guide:
View controller objects manage the presentation of your app’s content on screen. A view controller manages a single view and its collection of subviews. When presented, the view controller makes its views visible by installing them in the app’s window.
The UIViewController class is the base class for all view controller objects. It provides default functionality for loading views, presenting them, rotating them in response to device rotations, and several other standard system behaviors. UIKit and other frameworks define additional view controller classes to implement standard system interfaces such as the image picker, tab bar interface, and navigation interface.
http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/AppArchitecture/AppArchitecture.html#//apple_ref/doc/uid/TP40007072-CH3-SW1

It's good for views to have properties, but don't mix model logic into a view. The properties in a view should describe how the property looks, not what the property holds. I would avoid having a property named valueLabel in a view.
An example of view property names is UITableViewCell. It has properties imageView, textLabel, and detailTextLabel.

It's perfectly reasonable for a UIView subclass to have properties. You might need them to implement layoutSubviews, for example.

It is perfectly reasonable, also if you want to create a reusable component that allows for interaction and better flexibility, take a look at UIControl (which is a subclass of UIView)

Related

providing common functionality for different viewcontrollers in objective c

I have many viewcontrollers which needs to have some common functionality related to navigation.
Earlier I made a base class BaseViewController(extending UIViewController) which have all common functionality (like doing some tasks on viewDidLoad etc) and all my viewcontrollers extends BaseViewController.
The problem is that some of my viewcontroller should be subclass of UIViewController and some of UITableViewController, so I can not use above approach.
One way could be to write base class for both and duplicating code. Is there any better way without duplicating code.
While you can get around this by using delegation or helper objects, I would make the case for just not using UITableViewController. It is only a very light subclass on top of UIViewController, providing a table view, conforming to the delegate & data source protocols, and adding a property or two for selection & refresh.
While I wouldn't normally suggest recreating something that the framework has already done for you, it may (in your case) make your code more easy to understand if you just keep everything inheriting from a common base class and add a table view to one of the subclasses.
If you do think this would be a reasonable approach, the UITableViewController documentation overview gives a detailed description of exactly what & where these behaviours are implemented, so mimicking its exact setup is trivial.
Adding a table view to UIViewController
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) IBOutlet UITableView *tableView;
#end
In your storyboard, drag a "Table View" from the object library and drop it on top of your View Controller scene's "View" in the Document Outline - this will replace the root view with a UITableView.
Then just hook it up:
ctrl-drag from the view controller to the table view to hook up the view and tableView outlets
ctrl-drag from the table view to the view controller to set the delegate and dataSource outlets.
Done - no magic required.

Create Relationship Segues

How can I create a relationship segue? I would like to create a UIViewController subclass similar to UITabBarController or UINavigationController where, using Interface Builder, I can control + drag from a view controller to another view controller. I have tried
#property (nonatomic) IBOutlet NSArray *viewControllers;
#property (nonatomic) IBOutlet UIStoryboardSegue *root;
and also tried dragging a Container View into my view controller. When I do that, I can drag from one view controller to another but I cannot drag to more than one view controller. I also cannot find any documentation for a UIContainerView object.
Relationship Segues are handled by Interface Builder. You cannot create them manually if the starting view controller is not one of those you mentioned. The simplest solution for your issue is to create a TabBarController and hide its tab bar in code.
Here is a quite advanced tutorial on something very similar to what you are trying to do. You may get some more ideas from it. Advanced Storyboard Techniques
EDIT:
Thanks for the tip about using a TabBarController, but I am asking this question because I am trying to subclass UIPageViewController so that I can create the PageViewController's datasource from IB
That's an interesting idea, and here is an explained solution for that: Using UIPageViewController in storyboards You don't have to subclass the UIPageViewController, it is against the recommendation in the documentation, too. Create a class that implements the UIPageViewControllerDataSource delegate. Place a "green cube" in the page view controller's listing panel and set its class to be newly created one. Then drag from the datasource outlet to this cube.
However, the pages cannot be set up visually in this way or any other. It is unfortunately not supported at all.

Modify and redraw another UIView from the UIViewController

I have a flow issue in my iOS app from my subclassed UIView to its parent UIViewController.
Basically, I have a nib called preferences. It contains two sliders, two labels, and another UIView that will display a shape dictated by the two scroll bars (Stroke and opacity). I successfully painted the subclassed ui to the screen by setting the custom class of the UIView to a separate UIView we'll call subView. I have setters/getters for the scroll bars and they print out their values. How do i let the uiview class (pointed at the ui nib object) to update and redraw since it isn't referenced in the parent preferences class? I tried syntax like this:
[code]
IBOutlet SubClassUIView *subclassUI
[/code]
to no effect. It seems best to point a custom class at the UIView.
Any suggestions and advice would be much appreciated.
TL;DR can't modify subclassed uiview from "parent" uiviewcontroller
Sorry folks, i figured it out.
In addition to passing in a custom class that shares the same type as the IBOutlet (such as a UIView),
there MUST be a link referencing every object in in the .xib to its parent. In this case, the parent UIViewController needed a reference from the custom class ui to a IBOutlet UI. From there, some simple casting from generic and boring UIView to the custom class's unique methods makes for a complete flow.

Confused in UIKit view hierachy

I am little bit confused for unusual view hierachy present for UIWIndow.
If any one refer to apple UIKit Reference for UIWindow then UIView is the super class for UIWindow
NSObject->UIResponder->UIView->UIWindow.
But when one create a new project in XCode, there is a single MainWindows.xib and it contains the rest of views in the project.That means UIWindow is the super class for UIView.So UIWindow is child as well as Parent of UIView.Thats very confusing for any one.
So can any one have the clear idea related to this.
Don't confuse inheritance hierarchies with view hierarchies.
A UIView instance can have many subviews of type UIView so a UIWindow is a UIView and so it can contain other UIViews as subviews.
Look at all the other UI components like UIButton or a UILabel they are all inheriting from UIView, so you are able to add them to your view as subview.

An UIViewController inside other UIviewController and IBActions

I'm designing an iPad app where little UIScrollViews have their own UIViewController . Those controllers have in their view a button that call an IBAction method. But it isnt working, in fact, it doesnt seem that they are being pressed in the simulator.
Here is some code to give you an idea of what im am doing .
// In UIViewController A (say the parent or root that have several UIScrollViews)
MiniViewController * mini = [[MiniViewController alloc]init];
[scrollView1 addSubview:mini.view];
//repeat the same process a couple of times with different uiscrollsviews and instances of miniviewcontrollers
Now The MiniController is very simple as you can guess, i only post the .h file
#interface MiniControlador : UIViewController {
IBOutlet UIButton * button;
}
#property (nonatomic, retain) IBOutlet UIButton * button;
- (IBAction)doSomething:(id)sender;
#end
You can see that i used Interface builder to connect an UIButton "button" to a method called doSomething. But as i already said, it isnt working.
One more thing. I also tried to add a button to the UIScrollView with the Mini Controller instance programmatically.And it worked! But I certainly believe that it's extremely hardcoded.
What do you think? I'll appreciate any suggestion(s).
Apple's View Controller Programming Guide is an important read, and explains a lot about Apple's philosophy of one-view-controller-per-screen.
Much of the behavior of view controllers is built on the assumption that there is only one view controller operating at a time. When that assumption is violated, the behavior is undefined (or at least undocumented). In this case, your description suggests that the normal view controller behavior of inserting the controller into the responder chain between its root view and that root's superview (usually the previous screen) isn't working.
While you may find methods of initialization that do work properly, they're not going to be guaranteed to work, and the behavior is liable to change with future OS updates.
Edit: A relevant quotes from the View Controller Programming Guide:
Each custom view controller object you create is responsible for managing all of the views in a single view hierarchy. In iPhone applications, the views in a view hierarchy traditionally cover the entire screen, but in iPad applications they may cover only a portion of the screen. The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple custom view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.
Thanks guys, I finally solve this using objects of a class (that I called GenericViewController). It actually acts like a regular UIViewController, the IBActions responds well to any event (i.e. buttons being pressed).
I used an IBOutlet UIView in order to contain UILabels, buttons...and so on.
Here is some code if anyone is interested.
#interface GenericViewController : NSObject {
/* Some IBOutlets here*/
//like a regular UIView of an UIViewController, this holds the rest of the outlets
IBOutlet UIView * view;
}
//some IBActions here
}
Then the UIScrollView only add the view of each GenericViewController object
[scrollView addSubview:genericViewControllerObject.view];
If anyone has a better solution, please let me know :)
Are you sure you are loading the view from the xib you made in InterfaceBuilder?
I'm doing something similar in my app, and it's working for me.
I'm implementing the init method like this:
- (id)init
{
if (self = [super initWithNibName:#"__your_xib_name__" bundle:[NSBundle mainBundle]])
{
// TODO: Add additional initializing here
// ...
}
return self;
}
If you are not loading the view from the xib, then there will be no connections made (no IBOutlets initialized and no IBActions triggered).

Resources