Uniquely differentiate UIViews - ios

I have an application where every view controller subclasses from BaseViewController (A custom view controller that subclasses from UIViewController). I need to differentiate the subviews of a certain view controller's view from each other, from the BaseViewController. The application is pretty huge and each subview doesn't necessarily have a tag. What other ways are there to differentiate the sub views?

The application is pretty huge and each subView doesn't necessarily have a "tag". What other ways are there to differentiate the subViews?
That's exactly what the tag property is for -- differentiating between views that are otherwise similar, like each button in an array of buttons. You should only need to differentiate between the subviews managed by a single view controller at any given time; any given view should only be known by the view controller that manages its parent view, so the size of the app really doesn't change the tag property's utility.
The other obvious way to tell the difference between views is to use the fact that they're distinct objects, each with its own address. For example, say you've got a bunch of similar views representing people on a seating chart, and you want to keep track of which view goes with each person in the chart. One way to do that is to have your view controller maintain a NSDictionary where the keys are people and the values are the views.

XIB and Storyboard files are just XML. You could write a script to load the XML, put in tag attributes and save. The XML element name tells you what kind of view it is (button, imageView, etc).
Alternatively, if you can have different tags on each load, you can just programmatically tag the subviews in viewDidLoad

Related

Creating individual View Controllers for each view iOS?

This is a very simple simple question, and I believe the answer is “yes, it’s a best practice,” but I just wanted to ask the question.
When creating new views in your storyboard in Xcode, is it a good idea to create individual custom view controller files to handle each view specifically?
Meaning, if I create a new view called “login quiz,” should I create a “loginQuizViewController” that will handle all the code I write for that view?
Short answer:
Yes, each storyboard scene generally has a unique view controller class associated with it. A view controller has a root view, which in turn may have many subviews below that, and each subview might have further subviews. This collection of views is collectively known as the “view hierarchy”.
Long answer:
Yes, each storyboard “scene” has a view controller associated with it. And generally this view controller class is a particular UIViewController subclass which is unique to that particular Interface Builder scene. But you don’t necessarily have to have a view controller subclass and might, for example, use one of the existing classes (e.g. this is not uncommon for navigation controller scenes or tab bar controller scenes).
But if you have any custom logic associated with a particular storyboard scene, then, yes, you would generally have a unique view controller subclass for that particular scene.
Two minor clarifications:
You refer to the “quiz view”.
That’s fine for colloquial purposes, but for the sake of clarity, when we’re talking about everything for this quiz, it’s really a complex hierarchy of views, not just a one.
A single “quiz” scene will be associated with a unique view controller class, and the instance of that view controller class will have a single “root view” (identified with the view property), but that view will have a whole bunch of subviews (e.g. image views, buttons, labels, etc.), and some of those may have subviews of their own.
So one storyboard scene has its own unique view controller class, but is associated with a whole hierarchy of views.
We often think of a scene, and its associated view controller, as representing everything you might see at any given point in time, but it’s not always a one-to-one relationship. Sometimes what you see is composed of several storyboard scenes and their respective view controllers.
For example, if you are using a navigation controller, the navigation controller takes care of the navigation bar at the top, and your view controller might take care of everything under the navigation bar. What is visible on screen is composed of these two view controllers.
Or, in a more extreme example, we can define our own view controller containers. In the example below, when we present A, we can define the bottom half of the screen to be managed by a completely separate scene, B, which has its own view controller:
In this case, both A and B have their own IB scenes and their own respective view controllers. Achieve this by adding a “container view” to the A scene (the light blue UIView in the above screen snapshot).
But the main point is that what you see on screen may be captured by a single storyboard scene and view controller, or it might be composed of several.
A view controller can and probably will contain multiple views apart from the root view it has. That means that usually a view controller owns one ore more views that are subview's of it's own root view. Those views are often also controlled by the same view controller.
When coming from the storyboard most items you see are actually representations of view controllers (others are placeholders). "Login Quiz" sounds like a screen in conceptual terms, so (without knowing your details) it would probably make sense to create a LoginQuizViewController.

Multiple Variations of UI for the same view controller

I am working on an Exercise App, where UI depends on the type of Exercise. Some exercises have the question as text and answer as text. Some exercises have the question as text and answer as images. One more variation is image and text in question and image in the answer. I create a question object based on the values I get from API for a particular Exercise. That object has many fields as optional. For example, the image is optional. Now the challenge I am facing is what is the best way to handle such dynamic UI. In plain English, if it has the image, show the imageView and if it doesn't have the image, don't show the imageView and adjust other UI elements accordingly.
You can have one UIViewController subclass, and many different storyboards each with a different layout and subviews.
Each storyboard has the view controller's class set to your custom class in the identity inspector.
Your view controller has outlets for all possible subviews, and each storyboard connects its subviews to the outlets that are relevant to it.
When you need to present a particular variation of the string, you instantiate your view controller from a case-specific storyboard (programmatically or using segues and storyboard references).
If you only need to disable one particular subview in one case, you can do one of the following:
Set that subview's isHidden property to false. It will stay in place, and occupy the same area, but invisible.
Remove it from the main view by calling removeFromSuperview(). Be careful if other, remaining subviews rely on constraints against the removed subview for their layout, though.

Do I need a ViewController container or a composite view?

I need to implement an accordion control for iOS. By accordion, I mean a UI like this:
I see two basic ways to do this, but I'm not sure which one to choose.
Method #1: Create a ViewController container, something like a UITabBarController, except that instead of showing tabs at the bottom, I draw a vertical stack of buttons, and when you tap one, the corresponding panel opens and shows the corresponding view controller's view.
Method #2: Create a composite view, add a bunch of views directly to it, and show/hide them as needed.
How do I choose here? What would make me want to treat the sub-units as view controllers vs views?
Generally speaking, if I can avoid it I try not to subclass UIView and instead do everything within UIViewController subclasses. A controller is usually required anyway (model/view glue code, user interaction, delegate stuff, notification handling, etc.), so if no custom drawing is needed it is usually possible to do without a UIView subclass.
In your case I could envision one reusable UIViewController subclass that represents a list entry. It has the following responsibilities:
Create two alternate view hierarchies (collapsed/button, expanded/panel)
Toggle between the view hierarchies in reaction to user interaction (with/without animation)
And another UIViewController subclass that represents the entire list. It has the following responsibilities:
Override the appropriate methods from UIViewController to make it into a container VC
Add/remove child VCs as appropriate to the internal model
Possibly adjust the container view in reaction to collapse/expand events in its child VCs

iOS MVC architecture - separate view other than the view of view controller

Overview
I am doing an iOS project using the MVC architecture. Pardon my ignorance, I am just confused, I am looking for a good design.
The view I am planning to use will have some buttons on it and some labels and text fields. My view wouldn't need any custom
implementation of drawRect.
All my logic as to what needs to be done when a button is pressed or event occurs is in my view controller
I have a couple of doubts:
for the above scenario, is it still better (good practice) to create a separate view (a view other than view controller's view) ? If so why ?
Other than drawing and displaying the view (in my project, I don't have much of it) what else should a view's implementation code
contain ?
I would like to disable a set of buttons when the user touches on a textfield and the keyboard comes up.
a) So should I place this logic of disabling some buttons in the separate view's implementation (view created in question 1) ?
b) From my parent view (view created in question 1), can I create outlets to the buttons (which are subviews) to disable some of the buttons ? I am not able to do this. Or should I use the method subviews and loop through the button that i am looking for ?
My understanding
Model contains the data
View is responsible for displaying and shouldn't contain business
logic.
View controller is the only one to interact between the model and the view and contains the business logic
There's no need to create a separate view -- the view controller's view (usually just a plain UIView) can certainly contain your buttons and text fields. If you did want to put some of those in a separate container (perhaps so that you could move them as a group), you could use a plain old UIView for that.
Views are responders, so UIView subclasses can override the touch handling methods if you want to do any special touch handling.
a) It's common to put the code that manages views (such as disabling buttons) in the view controller. b) Again, you'd normally put the outlets for your buttons in the view controller.
When people talk about "business logic" they usually mean the logic that's required to maintain and operate on the data that the application deals with. That sort of thing is often best placed in the model. On the other hand, code that manages views, such as enabling or disabling buttons or moving data from the model into views (or vice versa) belongs in the view controller.
Q1. for the above scenario, is it still better (good practice) to create a separate view (a view other than view controller's view) ? If so why ?
If you create your view by Interface Builder, that's a separate view I think. ;) But if you try to create a view hierarchy programmatically without using a n/xib, you can put all your view layouts in loadView method, and populate the data in viewDidLoad, that's what the View-Controller does. And also, you can create a UIView class to implement the layout of the view, just like n/xib, but programmatically.
As the DOC said,
... 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. ...
... A view controller is a controller that concerns itself mostly with the view layer. It “owns” the interface (the views); its primary responsibilities are to manage the interface and communicate with the model. Action methods concerned with data displayed in a view are typically implemented in a view controller. An NSWindowController object (also part of the document architecture) is an example of a view controller. ...
The MVC in Cocoa is a litte different as what you known. You can refer the official doc HERE.
Q2. Other than drawing and displaying the view (in my project, I don't have much of it) what else should a view's implementation code contain ?
You can customize your view, e.g., set text color or font style for your button, etc.
Q3.a. So should I place this logic of disabling some buttons in the separate view's implementation (view created in question 1)
It is better to put logic in controller (or view-controller), just as MVC prefer.
Q3.b. From my parent view (view created in question 1), can I create outlets to the buttons (which are subviews) to disable some of the buttons ? I am not able to do this. Or should I use the method subviews and loop through the button that i am looking for ?
You can set tag (setTag:) for your buttons and get the right one you want. But keep in mind, firstly you need to let the button shown to parent.

Using multiple nib files with a single view controller?

Background
I'm using interface builder to create the UI for an app I'm working on. The app has a single screen that displays a series of buttons. Clicking on a button displays an associated view which overlays the buttons. Clicking another button hides the previous overlay view and displays another one.
Too make managing the UI easier in IB I've decided to create multiple nib files for each sub view that is to appear when clicking the relevant button. I'm then loading the sub view's nib file in the view controller's viewDidLoad method using the UINib class.
The idea behind this was to avoid having multiple views stacked on top of each other in a single nib file as this would be hard to manipulate in IB. I could have created all the views in code but this would require a lot of tedious coding as the layouts of each sub view are quite complex (with multiple child views).
Example code loading a sub view from a nib file.
- (void)viewDidLoad
{
UINib *aSubViewNib = [UINib nibWithNibName:#"aSubView" bundle:nil];
NSArray *bundleObjects = [aSubViewNib instantiateWithOwner:self options:nil];
// get root view from bundle array
UIView *aSubView = [bundleObjects objectAtIndex:0];
[self.view addSubview:aSubView];
...
The code above is repeated for the other views.
To summarise I have a single screen iPhone app that has layered views that are shown/hidden by clicking buttons. This is achieved with a single view controller with an associated nib file and a series of additional nib files for the sub views which are loaded in the view controller's viewDidLoad method.
Questions!
Sorry for the long introduction but I wanted to be very clear what it is I am doing.
Is my approach bad or unusual?
Are there any potential issues to doing it this way?
What have other people done when they need a dynamic interface and
still want to keep everything in Interface Builder?
Notes
Before anyone asks why don't I just display the sub views on a new screen and use the navigation bar, let me say that I have very good reasons and I do understand iOS UI guidelines. The above use case is not exactly my use case but it's one that clearly describes the problem without getting bogged down in my development app.
Also I know I could have written all the sub views as code but each sub view has a complex layout of child views and it would be a lot of code and messing around to try and get them looking right.
Thanks in advance.
There isn't necessarily a 1-to-1 relationship between view controllers and views. Most views contain many subviews, which are views themselves, so this literally doesn't make sense.
However, depending on the complexity of the views (including their content), you may want separate view controllers... or not.
For example, if you have two sbuviews that are each tableViews, you may want to have one view controller for each tableView. This is because each tableView is looking at the same delegate methods, and if they are in the same viewController, then the delegate methods have to differentiate between the tableViews. The delegate methods have signatures that allow this, but, in my experience, it can really make for a messy code design that is hard to follow and hard to manage.
On the other hand, you may have two tables that are managed by the same viewController, where one table is filled with meaningful data and the other is simply a place holder (as when the data source is empty). One might be visible while the other is not. Why make you life complicated by creating two view controllers when both are driven by the same data source (the model)?
In my mind, it comes down to how difficult it is to follow and manage the code. If the complexity of using a single view controller becomes burdensome, consider using more view controllers.
UPDATE
By the way, I have an example that I am currently working with that may illustrate a similar situation. In the InAppSettingsKit, that a lot of developers use, there are several xib files for pieces of the main view. You can look at the structure here on github. There is one main view controllers and several xib files. (There is also what I would call a "helper" view controller and an email composer view controller.) In this example, the xib files may be used multiple times to specify the layout of table view cells. There is no view controller for each xib file, though. (The documentation for InAppSettingsKit is sparse, so these things may not be obvious just by taking a quick look at it.)
Every View should have a corresponding UIViewController. Using one ViewController to "Control" more than one view breaks the MVC paradigm. "Controlling" multiple "views" from one controller will make it much harder to change one thing without breaking something else. The choices you make on how to present the content to the end user will be different for every individual. So if you say a NavigationController won't work in your case, maybe a Modal view is the answer or, you might just instantiate your custom UIViewControllers and add them to your view ([addSubview:]), if thats the road you want, but like I said, it would be beneficial for you to make a "controller" for each view object along with the corresponding xib. If you need information sent back, use a delegate or use Notifications to send the message back to the parent view. I learned the hard way that not following MVC paradigm, will make you life miserable. Try and keep your code as decoupled as possible. And read up on the MVC design pattern, you won't regret it.
actually its possible to do this.
Open your .xib file,select File’s Owner(in placeholder) -> "identity inspector" (utilities) -> change class name to your controller classname -> press control and drag file's owner placeholder to View object, select "view" in dialog.
Now you can customize your view.
p.s. you can use the same outlets as first xib, you need only to drag them to the new xib(+control sure).
here is an explained tutorial:
http://irawd.wordpress.com/2013/09/05/how-to-link-a-xib-file-to-a-class-and-use-2-xib-files-for-iphone4-and-iphone5/

Resources