Trouble understanding viewControllers in iOS - ios

I'm new to obj-c/iOS and I'm having trouble understanding conceptually at least viewControllers. I've read a lot of the Apple Doc's, I've even used viewControllers to some extent in xCode, but I still don't quite get what they are, or what are the best ways to use them.
I've been an AS3 dev for many years so my mind works in the context of MovieClips/Sprites and the Display list to get graphics on the screen.
Ok so from my understanding...
A viewController is a kind of class that handles graphics in some
fashion and then allows you to do something with them?? What is it in it's most basic sense?
You seem to add viewControllers to a Window class, which I guess is a bit like
adding a display Object to the Display list?
What is it that a viewController does for you in it's most basic sense?
Are there certain things you definitely can't do with them or shouldn't do
with them?
Do viewControllers need to be connected in some way to the rest of the iOS framework to function (apart from being added to a window).
How exactly do they use data? (I've read up on MVC, I understand that conceptually this is a slightly different question) as I understand it you don't hardcode data into a viewController, so how does a viewController access any static data?
Let's say I just wanted to throw an image up on the screen, exactly what part would the viewController play in that process? is it just something which handles only one small aspect of that process or is it the whole show and handles everything?
Does one viewController handle multiple images? is it like it's term, a "controller" for all the images presented on screen, or does it handle one image at a time?
What is a viewControllers connection to the image(s) it handles? it contains references to them?
I'm using the Sparrow framework which is helping but I would still like to be able to get my head around what viewControllers are so I know how to use them properly.
Ha, I apologise for the above I know it must look like I'm completely confused :) thanks for any advice.

Hope this helps you:
A viewController is a kind of class that handles graphics in some fashion and then allows you to do something with them??
It's the glue between a View (Xib File) and the Data (Could be
CoreData or whatever you're using in the backend). All the UI Elements
you are using in the View you normally define as properties in the
controller to get access to them.
What is it in it's most basic sense?
You seem to add viewControllers to a Window class, which I guess is a bit like adding a display Object to the Display list?
I don't really know AS3 so I cannot compare Display lists with ViewControllers. But basically ViewControllers are there to handle
different types of transitions between the views and accessing
(setting/reading) the data which is displayed in the view.
What is it that a viewController does for you in it's most basic sense?
Like I've written above. Most basic sense they interpret what the user
does on the view and depending on the action of the user changes the
model.
Are there certain things you definitely can't do with them or shouldn't do with them?
It is always hard to keep the border between model and controller.
They are pretty close to each other. So what I normally try is to
delocate all logic stuff (like calculations, database access and so
on) this does more belong into the model part. But of couse you're
using these external classes in the controller.
Do viewControllers need to be connected in some way to the rest of the iOS framework to function (apart from being added to a window).
Well like you already have written the ViewController needs to be
connected to a view. Otherwise it would not make much sense. There are
different subtypes of UIViewController such as UINavigationController
where you probably need to overwrite some other methods to provide the
whole functionality wanted by these special subtypes.
How exactly do they use data? (I've read up on MVC, I understand that conceptually this is a slightly different question) as I understand it you don't hardcode data into a viewController, so how does a viewController access any static data?
There could be different approaches to store the data. Simplest way
would be to have the data directly stored in the UIViewController.
This could be a custom class which is the container of the data. All
changes are directly written into this class and displayed by the
UIViewController. But in most of the cases it makes sense to use
CoreData (Which is responsible for reading/writing the data into a
sqlite database). You could look at CoreData as your model and the
UIViewController gets the data from there and passes the data which
the UIViewController has received from the View back to it.
Let's say I just wanted to throw an image up on the screen, exactly what part would the viewController play in that process? is it just something which handles only one small aspect of that process or is it the whole show and handles everything?
The UIViewController would store an internal Property (UIImageView *)
which is in the Interface Builder connected with the UIImageView you
have created in the Xib file. So over these property you can change
through your Controller the image.
Does one viewController handle multiple images? is it like it's term, a "controller" for all the images presented on screen, or does it handle one image at a time?
Yes, this isn't a big problem. You can have as many images you want.
You just need to have the properties defined in the UIViewController
and linked to the View.
What is a viewControllers connection to the image(s) it handles? it contains references to them?
Yeah, its like a reference to the UIElement. You can then change
whatever property of the UIImageView you want directly from the
UIViewController
Some useful links:
Apple Official ViewController Guide
Apple Official ViewController Basics
You should have a look at Storyboards (U can use them since IOS 5.0)

I recommend you to check:
https://stackoverflow.com/questions/1939/how-to-articles-for-iphone-development-and-objective-c
Here are the answers to your questions:
No, it's doesn't handle graphics. It's the controller of the MVC design pattern. It handles the lifecycle of it's contents (for instance the views) and the data linked with.
A UIViewController is set as a root of an UIWindow. For instance, a UINavigationController is a subclass of UIViewController that stacks UIViewController in order to deal with the navigation.
Response in (1)
Try to be more specific with this question please.
As already commented, it's useful if you use the already built-in components like UINavigationController or UITabBarController.
For instance, you can have the data in instance variables and the display them in the contained UIView.
The UIView attached to your UIViewController will contain an UIImageView. Your UIViewController would have a connection with it in order to whatever changes you need, for instance, changing the image when the user press a button.
It can contain multiple UIViewsand therefore multiple UIImageViews (it's a subclass of UIView)
As commented, they would be contained on an UIImageView and would be linked programmatically or with an IBOutlet.

In a nutshell, a view controller is the controller in the MVC pattern. Please check this link before reading further so you're up to date with this pattern:
http://developer.apple.com/library/mac/#documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
OK, basically a controller manages a collection of views. It also fetches data from your model and sets the state of the views. It's important to note that the views know nothing of your model (your data), and the model knows nothing about your views. A controller also receives events from the views and decides how to change your model accordingly. It is essentially managing the synchronisation between your views and model.
There are technologies that help automate this such as KVO and key value binding. A google search will help you there.
One more thing. No other part of your application should access your views except for the controller. So generally in an application controllers tend to communicate with each other, for example via transitions or the delegate patterns between controllers under a navigation controller. So your application backbone tends to be controllers talking to each other.

Related

What is proper MVC structure for embedding a custom view within another view?

Thinking it over, this feels like a bit of a noob MVC question, but I can't come up with or find a definitive answer so I feel I should ask and get some clarity for myself.
I have a custom view that I created using a xib. It is going to be used in, currently, 4 other places in my app. Each usage has identical functionality, so I'm basically just creating a custom control object that I can reuse multiple times.
My "control object" consists of a UITextField, and two UIButtons.
The functionality I'm looking at implementing is, the first button will bring up a UIPicker and the 2nd button is essentially a done button and will just resignFirstResponder on the UITextField. As previously mentioned, this is consistent everywhere this will be used.
What I'm curious about is, is it ok for me to build this functionality directly into the custom UIView subclass since it is consistent behaviour for all instances of my control object? Or, do I need to create a custom UIViewController subclass to go along with it?
Currently, in my main UIViewController for my app I am creating instances of my custom UIView "control object" and treating them the same as any other control object. If I should actually be creating a custom UIViewController class to go along with it, well, I'll have more questions for another thread as to how I should be doing that (unless someone can direct me to a resource on this)
So far, searching the web has yielded nothing for me and from everything I've seen so far with iOS development in general, I've gotten the vibe that UIViewControllers are really only ever for a main, presentable view (that takes up the entire screen.. I might be missing some terminology for this).
My gut feeling is that no view controller is necessary in the scenario I'm describing, but I'd like to try to get some sort of confirmation, if possible.
There is no silver bullet, so no approach is absolutely right or absolutely wrong. What you describe here is just a view that changes its states. So putting everything in your UIView subclass is completely OK. It also conforms to the KISS principle.
However, as far as I understand, and correct me if I'm wrong, the input of your custom view - the text and the picked value from the picker does not really affects the view itself, but the viewController it's attached to. So you need to pass that input to the hosting viewController. This can be achieved by protocol with a default implementation. So the handling of the input data is written only once, but can be attached to whatever viewController you want.
Based off of everything that you've said, I see no need for another view controller. I can see where the answer could be a little unclear considering that the actions are something that ViewControllers usually handle, but I think you'll be just fine letting your custom view handle this by itself.
If you add more functionality or more complex operations, then perhaps it is time to explore other options but for now I think the single view will be fine.

iOS -- When to create a child ViewController vs. a UIView Subclass?

Maybe this is a silly question, but I've bumped into it a number of times during iOS Development.
Sometimes I'll develop a view component that I want to use on multiple screens, so I'll decide to subclass UIView and make it something I can use in multiple places.
Then, I start adding functionality to it. Maybe it needs to respond to an NSNotification, or it is supposed to respond to user touches.
At a certain point, I start wondering if I should really be making a UIViewController subclass, and add it to my UI as a child ViewController.
Is there any consensus on where to draw the line between adding some behaviors to a UIView, and when to create a full UIViewController?
I can't tell you about the consensus, but here's my opinion:
Subclass UIView only when...
You want to do custom drawing
You need to customize some behaviour of an already existing UIView subclass
You have special needs for layouting subviews. Most layouting can be done by UIViewController, though.
Maybe for special touch handling that you can't be done with gesture recognizers
Subclass UIViewController in all other cases. You almost always need a controller anyway, for writing glue code that ties together views and models, or for handling user interaction. Consequently, Apple has made it easy in UIKit to let controllers do all the work and to keep views as "stupid" as possible. For instance, it is very simple to nest controllers to create complex view hierarchies, without the need to have a single view subclass.
An indicator that subclassing UIView is not the first thing one should do is the section titled "Alternatives to Subclassing" in the UIView class reference. An indicator that subclassing UIViewController is the preferred thing to do is that there is no such section in the UIViewController class reference :-)
You should use a controller anytime that you need to handle or control data. Views are supposed to be as stupid as possible, not knowing what they are displaying but rather where. You can easily subclass and reuse ViewControllers. A good example, say you need to retrieve a string (or text) from the user throughout your app via a popover controller and a modal. Create a generic subclass of UIViewController that has a view with a textfield and a button. You can then use this view and it's controller in any capacity you need. Reusing it in the popover, modal or anywhere else (and generally passing the data back through delegation). Since you are dealing with data you should not being using a sole subclass of UIView.
From my experience I subclass UIViewControllers more often then UIViews. It is a little difficult for me to understand if you are solely talking about Containers or reuse of views in general application workflow. Either way though it should be the same.
I've used the embedded view controllers to load reusable table views from time to time. I've found that it's useful sometimes but not always. Communication between the two can be cumbersome, like if you want the embedded controller to communicate back up to the container. Delegation makes it easier but still cumbersome. It also limits you to iOS 6, if I remember right iOS 5 and lower don't support embedded controllers.
If it's just adding methods you can use a category to store some extra methods. I do that a lot on NSManagedObjects that I don't want to subclass and if I regenerate the NSManagedObject from the datamodel I don't lose the code in my categories. Gives me added functionality like calculated fields or conversion methods without having to subclass. If you don't need those methods for a particular instance just exclude the reference to the category.
Subclassing never is bad though IMO.

In iOS, is it a good pratice to build an generic UI Component using UIViewController?

If I want to build a generic UI Component (one that will handle its own view and logic, data source,
etc), is it a good practice to subclass UIViewController?
I would say no. But it depends. If your component manages other view controllers or has/will have any kind of logic that's not specific to a view (e.g. navigation logic, business logic etc) , then you should subclass a view controller. Then again that makes it more than an UI component.
Otherwise, you should subclass an UIView, like Apple does with many components, including UITableView (speaking of datasource), GLKView, UICollectionView.
My overly simplistic answer is "no, when building a generic component do not automatically start with a UIViewController subclass". However that alone is not a useful answer and in some cases a UIViewController subclass is exactly the right solution.
Instead let's consider how to decide what your component should be. I think the best way to figure that out is to answer three questions:
What is this component responsible for?
How do you want to interact with it?
What are its dependencies?
In all cases we can try to start as simple as possible and add complexity only when the answers to those questions require it.
Could this component just be a function? No objects, no classes, if all you want to add is some behavior then maybe all we need is a function. If this behavior only applies to specific existing types then maybe we need a category on an existing class.
Not enough to cover what we want to do? Ok, I guess we might be talking about a new type so let's create a class. Can it just be a subclass of NSObject?
Want to display something in a view? Ok, then we at least have a UIView subclass, maybe a UIControl subclass if it is more interactive.
The view needs some data to back it? No problem sounds like we now need two pieces; a view to display data and a data source to provide it. Here the view shouldn't need to know who creates and owns this data source. As long as one was provided to the view we can use it, anything else is outside of the view's area of responsibility. Similarly we might add a delegate to notify some other object of interactions with the view.
If we still haven't covered all of this component's responsibilities then maybe we need yet another piece, something in the controller layer to manage our view. We're still not (yet) talking about a UIViewController though! It's fine to have a "controller" or "service" that is a NSObject subclass. If all this piece needs to do is manage network connections, or map NSFetchedResultController results to our view's data source protocol and update the view, or just provide a convenient implementation of the most common mapping of model objects to the view's data source then a simple "controller" object is still all we need.
Still not enough? Finally we get to the point where we consider providing a UIViewController subclass. Maybe we want to allow users of the component to just present a modal view controller to hand off responsibility for an interaction (send an email, compose a tweet). Maybe there's a common set of default behaviors we want to provide that are tied to view controller life cycle events (UITableViewController flashing scroll bars in -viewDidAppear:).
Build your component from the pieces you need to support the behaviors you want to provide but keep it as small and simple as possible.
Yes, it's good practice in many cases. The iOS SDK contain many examples of UIViewController subclasses. A few of them contain only a small amount of generic behavior and are essentially useless without customization:
GLKViewController
UICollectionViewController
UITableViewController
And some of them provide significant generic behavior but are still mainly containers for your own view controllers:
UINavigationController
UIPageViewController
UISplitViewController
UITabBarController
But most of them are essentially complete packages with little or no need (or ability) to customize their behavior:
ABNewPersonViewController
ABPersonViewController
ABUnknownPersonViewController
EKCalendarChooser
EKEventEditViewController
EKEventViewController
GKAchievementViewController
GKFriendRequestComposeViewController
GKGameCenterViewController
GKLeaderboardViewController
GKMatchmakerViewController
GKTurnBasedMatchmakerViewController
MFMailComposeViewController
MFMessageComposeViewController
MPMediaPickerController
MPMoviePlayerViewController
PKAddPassesViewController
QLPreviewController
SKStoreProductViewController
SLComposeViewController
TWTweetComposeViewController
UIActivityViewController
UIImagePickerController
UIReferenceLibraryViewController
UIVideoEditorController
If you think about what all of these have in common, you may conclude that they all have two things in common:
Each has a specific model (in the MVC sense) that it interacts with, and that model is not specific to your app. The models vary widely (UIVideoEditorController's model is a single video; UIImagePickerController's model is the entire photo library; GKAchievementViewController's model is a database possibly on an Apple server in “the cloud”), in some cases you provide the model (or some properties of the model) up front, and in some cases you receive the model (or a fragment of it) at the end. But in every case, the view controller handles all the interaction between the user and the model with little or no ongoing help from your app.
Each provides its own view hierarchy, with little or no customization required (or even permitted).
In other words, each of these view controllers isn't just the “C” of an MVC pattern. It's the tip of an entire MVC iceberg.
If your component is also an MVC iceberg, then exposing the tip of your iceberg as a UIViewController subclass is quite appropriate.
It depends on the iOS version you used.
A. prior to iOS 5.0, It's not a good practice, and not recommend.
B. start with iOS 5.0, It's just ok.
subclass a view controller for a UI component (UIView), , that means you wanna use the view controller life cycle method, to manage the user interaction and view display procedure, data model etc. So, if the life cycle method can not easily automatic called, the view controller is not that meaningful.
start with iOS 5.0, it's possible to create custom view controller container, so, it's ok to build custom generic ui component with view controller to add as a child view controller.
prior to iOS 5.0. Subclass a UIView with custom delegate protocol is the right way. one other thing is about the code organize. put the all custom delegate method to another custom class, not in the view controller, in the view controller just init a delegate class instance, and set this to the view delegate property.

The correct way to communicate between several different view controllers in Objective C

I have an app that was extremely simple until today. It had a tab bar view controller with 3 tabs. The middle tab was a camera, and the other 2 were table views. The tab bar view controller was the central hub for all the data in the app. So from there, I would set a table's data array as:
(PLEListViewController*)[self.viewControllers objectAtIndex:0] setList:newList];
Obviously, PLEListViewController is my UITableView subclass.
So now, I want to wrap the table views in a UINavigationController, which is fairly simple. But now, that line of code turns into:
[(PLEListViewController*)((UINavigationController*)[self.viewControllers objectAtIndex:0]).topViewController setList:newList];
There are 15 lines in the code that do this, which is not pleasant.
So my question: what is a more elegant way of doing this that I'm missing?
It's good that you're asking this and seeing the issue now. Your problem is can be found in your question. The answer to "the correct way to communicate between several different view controllers in Objective C" is "don't." Specifically, your mistake is here:
The tab bar view controller was the central hub for all the data in the app.
A view controller should never hold any of the data in the app. Your data should live in your model classes. All the view controllers should talk to the model classes. They should very seldom talk to each other. That's the heart of MVC.
So, you move your "list" (whatever that is, doesn't matter) into some model object that all the view controllers know about. That model object can be a singleton, or often better, it can be passed to the view controllers when they are created. When things change, you change the model. And in viewWillAppear: you update your view controller to match the current state of the model.
Never assume that a view controller exists when it is not currently on screen. If your design requires that a non-active view controller exist, then your design needs fixing.
You need to work with your architecture. Make the appropriate datasource and delegation protocols to ensure your classes can communicate anonymously. What you currently have is very inflexible and it will get worse as your app grows/changes.
You want to make things more loosely-coupled, instead of coding explicit traversal of links between your objects in your code.
Assuming you have one data model that is displayed in various places in your application, I think there are 2 approaches that could help...
One is to use your view controller hierarchy.. For example, use [ self enclosingTabBarController ] to find your closest parent tab bar controller and get it's data model property. Substitute -enclosingTabBarController with what works better for your application.
The other approach would be a "data model as a singleton" approach. For this you can either
move the data to your application delegate and access it via ((MyApplicationDelegateClass*)[ UIApplication sharedApplication ].delegate).dataModel
or
have a singleton data model object for your app, and access it via [ MyDataModelClass sharedModel ]
In any case you are moving to a looser coupling, which requires less explicit traversal of links between objects in your app. Less is more!

What is the best practice to control multiple views?

I have this view in the storyboard:
as you can see there are some fixed controls, and others that change according to the type of screen.
What do you think is better?
1- Same view controller for multiple screens. (more code to control views)
2- Add all controls in the same screen, then hiding and showing them by code? (messy code)
3- View controller for each screen. (replicated code)
Don't use the word "window", which can lead to different interpretations of what you are trying to say. Use the word "screen", or "section of the screen". In this case, I would use a container of UIViewControllers. To communicate between then, use KVO or NSNotificationCenter (most probably the second one). Also make sure to not have the data source directly on the UIViewController (like an array or a dictionary). Keep the Data Source somewhere else, where all the UIViewControllers (or any class) can easily access. You could go with a Singleton.
Putting the Data Source away, and not directly on the UIViewController, gives you more flexibility over your code. If you ever need to use a new UIViewController, nothing is changed, he can still request resources from the same point. So keep that in mind.
Edit 1
The data source also is inside the view controller, there is no
interaction between screens, it's the same screen but some controls
changes according to the type of it, what do you think I have to do
now?
The problem with this kind of approach is that if you need, for some reason to add a new UIViewController, that also use the same data source, what do you do now? I always try to decouple as much as possible the UIViewController from the Data Source. Otherwise you might have problems in the future, if the application changes (client's needs change). Again, moving the Data Source to a proper class, and use a Singleton to access it.
UIViewController <=> Singleton <=> Data Source
So now you suggest to make multiple view controllers with multiple screens?
I suggest a UIViewController to act as a container for the others UIViewControllers. For me it makes more sense to compose the Screen as I go, than doing everything in one place.
I'd definitly go with no 3. This approach is most flexible! And it is clean => good to maintain

Resources