IBOutletCollection of UIViewControllers - iphone

I want to do something like UITabBarController. UITabBarController has property viewControllers into which I can add instances of UIViewController * in IB. I'm trying to do the same think with my own VC:
#property (nonatomic, copy) IBOutletCollection(UIViewController) NSArray *viewControllers;
but this doesn't work. Is it even possible for us?
EDIT 1.
Ramshad posted the proper sample, but using XIB. I would like to achieve it using storyboards.
EDIT 2. - at the end of bounty worth...
I question vaderkvarn's post because in case of UITabBarController it works. Also as Ramshad posted, it is possible in NIBs. So far, dasblinkenlight's post is the most correct, but not answers the question. I'm holding this question opened because we shall find out if it's restricted for us or what is the way.
PS: Why these downvotes?

Although it does not look like you can connect UIViewControllers to IBOutletCollections (or there are too many restrictions placed on using them), there is a simple solution that works when you use storyboards. This code goes into your viewDidLoad method:
_viewControllers = [NSArray arrayWithObjects:
, [self.storyboard instantiateViewControllerWithIdentifier:#"Controller1"]
, [self.storyboard instantiateViewControllerWithIdentifier:#"Controller2"]
, [self.storyboard instantiateViewControllerWithIdentifier:#"Controller3"]
, nil];

The reason why the outlet collection solution does not work is that a View Controller is not an outlet. From the documentation:
An outlet is a property that is annotated with the symbol IBOutlet and
whose value you can set graphically in a nib file or a storyboard.
A view controller is not a graphical object.
If you want to use an IBOutletCollection, you should only use one view controller, and put the views in the collection.
But if you want one controller for every view, you need to go for a more programmatic approach. An array with view controllers might be a good start, but I couldn't say as I don't know what you want to do with them.
Edit:
To be more clear as you don't seem to catch my point:
No, it does not has to be a way. A Storyboard is not an API, it is a graphical tool for drawing scenes and segues. It is specially designed for things like Tab Bar based apps.
If you right click on your Storyboard file and choose open as -> Source Code, you will see that a Tab Bar Controller have special elements that other View Controllers do not have. To mess around with the XML in a Storyboard file is beyond me.
If you want to go with Nib files, use Ramshads answer.
If you want to get as close as possible with storyboards, go with dasblinkenlights answer.
But the answer to your question (as far as I know) is NO, there is no way to accomplish this with storyboards. If it were, it would have been documented, which it is not.

I have done your requirement using UISegmentedControl + IBOutletCollection + presentViewController.
You can use any control instead of UISegmentedControl as your wish.
I have Added 3 different UIViewControllers to Xib and labelled as ViewController1,2,3.
I also added 2 extra methods. One for presenting the corresponding view and another one for dismissing the earlier populated view.
I have attached the Xib settings screen-shot below.
You can use only one UIViewController instead of 3 and reuse it with some logic :)
The methods are below:
#property (strong, nonatomic) IBOutletCollection(UIViewController) NSArray *ViewCollection;
//dismissing the earlier populated view
- (IBAction)dismiss:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
//presenting the corresponding view.
- (IBAction)resetAction:(id)sender {
UISegmentedControl *mySegment = (UISegmentedControl *)sender;
int index = 0;
for (UIViewController *viewItem in _ViewCollection) {
if (index == mySegment.selectedSegmentIndex) {
[self presentViewController:viewItem animated:YES completion:nil];
}
index++;
}
}
You can download the my sample application from here
Xib Settings Screen-shot

Related

own view controller template

here i want to ask a question regarding view controller template for iphone or ipad.
question: i want to design a view controller with some images and make it as common template and need to use it as a template to other view controller too. (also some buttons and labels are the inclusions if needed)
(ie) when ever i call that class, automatically its components should be inherited to calling class.
is it possible?
it would be grateful if anyone answers me the suitable or favourable
I don't know how adMob works but like everything else you can create a BaseViewController in which you can add your adMob(in the viewDidLoad method) and then all the other viewControllers can subClass this BaseViewController. just call [super viewDidLoad]; in the viewDidLoad methods of your viewControllers and you will have it...
hoping this sorts your problem... :) this is what I usually do.
Sounds like you just need to derive your view controllers from a common base class. Is there something that you want to do that's not provided by inheritance?
Yes it is possible.
You need to create #property for your components to re use them in other class
in class1:
#property(nonatomic,retain) NSMutableArray *exercisesArray;
in class2:
#property(nonatomic,retain) NSMutableArray *array;
nextViewController *start = [[nextViewController alloc]initWithNibName:#"nextViewController" bundle:nil];
next.array = exercisesArray

referencing views elements in xcode iphone programming

I am trying to do something really simple, but I can't find any examples and can't figure out.
I am coding in xcode 4 for iphone 5.
I have 2 views on my storyboard. One has a button (ButtonFromFirstView) which leads to my second view. The second view has a picker view object and a "select" button. When I click "select" it takes me to my first view. And I would like the ButtonFromFirstView title to be the string selected in the picker from second view. How do I get what value was selected in the picker view?
in my second view I have the following method which catches the changes in the picker. However ButtonFromFirstView is NOT available. How can I get to it? If the button is on the same view where picker is, that it works, but this is not what I want.
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
NSString *SelectedString = [DeparturePickerArray objectAtIndex:row];
[ButtonFromFirstView setTitle:SelectedString forState:UIControlStateNormal];
}
The general paradigm for iOS development is that each "screenful" of content should have a separate view controller. So, for each of your two screens, you should have a subclass of UIViewController, rather than a subclass of UIView.
Your question is essentially - how do you pass information between the two view controllers? In a situation as simple as yours, the best way is to hook them up from your app delegate class. So when you create the view controllers (e.g. from a nib), you want to create a method which you call like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
... (create view controllers)
[secondViewController setButtonToUpdate:firstViewController.buttonFromFirstView];
....
}
Within secondViewController, you then need to keep a reference to the button that's owned by firstViewController. So, something like this in the header file:
#interface SecondViewController : UIViewController {
UIButton *buttonToUpdate;
}
#property (nonatomic, retain) UIButton *buttonToUpdate;
This is a simple answer for a simple question, but to do things "properly", you would probably want to remove the dependency between the two view controllers, and look into using formal or informal protocols.
Also, iOS uses MVC (Model-View-Controller), which would dictate that SecondViewController should first send the string from the picker to some Model class that might then notify an observer such as FirstViewController that its data has been updated.
Does this make sense or do you need a more full explanation?
Check out "Introducing Interface Builder Storyboarding" in the WWDC 2011 Session videos: https://developer.apple.com/videos/wwdc/2011/. It shows you how to manage a sequence of views (or more precisely view controllers) in iOS, how to send data down to a detail view, and how to get user input or other data back. This video pulls together: (1) how to make the UI without programming, (2) how UINavigationController helps the screen flow, and (3) how to pass data back and forward, both using protocols and via a Core Data database. The parts that directly answer the question start at time 12:00.

xCode - Changing views between 2 existing xib-files

I'm very new to xCode and objective-C so I wanted to make a simple textRPG.
I'm currently making a character creation process consisting of 4 xib-files. The only way I got switching views to work was to look at the utility-template. Problem is, now I have the first screen being the delegate for the second screen, being the delegate for the third screen etc. So by the end of the character creation process I can't dismiss the views because that just "steps back" through the views.
When I've searched around for a solution I've found a addSubview-method but it seems like that makes a new view, like, empty to arrange programmatically.
All I need is a simple way to switch from one loaded xib to another xib. Have I misunderstood addSubview or do I need something completely different?
(If it helps: I've worked with VB for several years, in case you notice that I missed some kind of concept concerning views and such)
Thanks in advance! :)
Use this code. It is really simple and works well.
View *view = [[View alloc] initWithNibName:#"xibNameGoesHere" bundle:nil];
view.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:view animated:YES completion:nil];
This will switch to another xib file and the two views won't own one another. I am using it in my own game right now.
#Joakim Ok, this is the way I do it. I have a class called RootViewController : UIViewContoller, whose view I add directly to the window. Then I make a subclass of UIView i.e. MyView. All of my views then subclass MyView. I also make an enum for all my views. In RootViewController you should have a switchView:(int)view method that looks something like this:
-(void) switchView:(myView) view
{
[_currentView removeFromSuperview];
switch(view)
{
case titleView:
_currentView = [[TitleView alloc] initWithRoot:self];
break;
case homeView:
_currentView = [[HomeView alloc] initWithRoot:self];
break;
default: break;
}
[self.view addSubview:_currentView];
[_currentView release];
}
in #interface RootViewContoller define MyView *_currentView;
TitleView and HomeView both subclass MyView and have a common method -(id)initWithRoot:(RootViewController*) rvc.
To switch between views use [_rvc switchView:homeView];
Hope this helps :)
It is called UINavigationController. Idea is
1) You push corresponding 'next' controller into navigation controller each time user submits current screen. Bonus - you'll get 'back' button for free on each step of character creation.
2) After character is created you pop all character creation controllers from stack.
Please read View Controller Programming Guide for iOS before trying to 'switch views' and such. You'll save tons of time and nerves.
another idea is not to use interface builder at all. i have been working with iphone apps for two years now and found that interface builder really prolongs the time to actually make something. make your own root controller and think about the logic you need to navigate through the views.

iPhone: Proper use of View and View Controller

I've recently been doing a lot of Objective-C programming, and just got back into doing more iPhone development. I've done a lot of programming using MVC in other languages/frameworks, but I just want to make sure I'm using MVC properly in my iPhone Development.
I created a new iPhone Utility Application, which creates two views: MainView and FlipsideView. Both have a controller (FlipsideViewController and MainViewController) and XIB file of their own.
What I've been doing is putting the IBOutlet UIControl myControl variables in my MainView.h or FlipsideView.h files and then tying the controls in Interface Builder to those variables. Then I put any IBAction SomeAction myAction methods in the MainViewController.h and FlipsideViewController.h files and tying the events to those methods in Interface Builder.
This seems to be conceptually correct, but seems to cause problems. Say I have a button that when clicked it changes a label's text. So the Controller doesn't have a clue of what the variable name of the label is in the OnTouchUp event handler for my button. So I make a #property for it. But since the MainViewController.view property isn't of type MyView, I get warnings or errors whenever I try to access those properties from the view controller.
I am doing this correctly? Is there a better way to do this? If this is correct, how do I properly work with those variables without getting warnings or errors?
Thanks
Here's some code showing what I'm doing:
MainView.h
#import ...
#interface MainView : UIView
{
IBOutlet UILabel* label;
IBOutlet UIButton* button;
}
#property UILabel* label;
#property UIButton* button;
#end
MainViewController.m
-(void) buttonTouchUp:(id) sender
{
self.view.label.text = #"The button was pressed!"; //This gives error because label is not in the view structure or union
[self.view label].text = #"The button was pressed!"; //This gives a warning
}
I know I can cast the view to be of the right type, but that seems like a hack job.
I know I can live with the warning, but a warning says to me that I'm doing something that I probably shouldn't be doing. I don't believe the SDK would set me up to do have to do something like that all the time.
I must just be misunderstanding what the View is supposed to be and I'm using it incorrectly.
Most code I've seen and written myself keeps all the outlets and the actions on the controller. The button sends a message to the controller (via IBAction), then the controller updates the label (via IBOutlet). In other words, putting outlets on your views is unusual.
Views shouldn't be connected to other views unless they have some special relationship, like maybe back/forward buttons that target a UIWebView... but even then, you find out you need a controller to enable/disable the buttons as appropriate.

iPhone Views at Runtime?

I am new to the iPhone SDK and am trying to create 3 views and switch between them. Data will come from a server and I will basically be showing 1 view and caching the other two. So far I am just trying to create a view and display it at run-time. My code is listed below. It shows only a blank screen and I think I am missing a key concept. Any Help?
#import <UIKit/UIKit.h>
#import "ImageViewController.h"
#interface Test5ViewController : UIViewController
{
IBOutlet UIView *rootView;
ImageViewController *curImage;
ImageViewController *nextImage;
ImageViewController *prevImage;
}
#property(nonatomic,retain) IBOutlet UIView *rootView;
#property(nonatomic,retain) ImageViewController *curImage;
#property(nonatomic,retain) ImageViewController *nextImage;
#property(nonatomic,retain) ImageViewController *prevImage;
#end
and
- (void)loadView
{
self.curImage = [[ImageViewController alloc]initWithNibName:#"ImageView" bundle:[NSBundle mainBundle]];
UIImage *pic = [UIImage imageNamed:#"baby-gorilla.jpg"];
[self.curImage assignImage:pic];
self.rootView = self.curImage.view;
}
and
#import <UIKit/UIKit.h>
#interface ImageViewController : UIViewController
{
IBOutlet UIImageView *image;
}
-(void)assignImage:(UIImage *)screenShotToSet;
#property(nonatomic,retain) IBOutlet UIImageView *image;
#end
Welcome to the iPhone SDK!
In general, there are two ways to get any view displayed.
First, and most commonly, you use a NIB file created by the Interface Builder. This is usually the easiest way to get started and I would recommend it for what you're trying to do here. It's too lengthy to describe all the steps you need to do for what you have here, but basically start in xcode by creating a new file and selecting "user interfaces" and choose View XIB. This will create a basic NIB file (they're called NIBs rather than XIBs for historical reasons). The first step in interface builder is to change the class name of the "File's Owner" to your UIViewController subclass (Test5ViewController). You can then drop anything that IB will allow into the view window or even replace the pre-supplied view object with one of your own. And here's the trick: make sure the view outlet (supplied by the UIViewController superclass) is connected to a view. Once this is done, this view will be automatically loaded when your NIB is loaded. You can then just put your UIViewController subclass (Test5ViewController) in your MainWindow.xib NIB file to get it automatically loaded, and you're in business.
Now, the way you're doing it here is the second way. Some people like to code this way all the time and not user interface builder. And while it's definitely necessary sometimes and always more flexible, it makes you understand what is happening a bit better. There may be other things, but the main thing you're missing is that in your code above, you have nothing that is adding your view into the view hierarchy. You need to check first that you have an UIApplicationDelegate subclass and it needs to load your "root" UIViewController class. All initial project creation types in xcode do this (except Window-based application). It is code like:
[window addSubview:rootController.view];
Once this is done, if your view controller wasn't loaded by the NIB (described briefly above), your loadView method will be called, expecting you to build your own view hierarchy. Above, you created the view(s), but failed to put them in a hierarchy. You need something like:
[self.view addSubview:curImage.view];
No view will be rendered until added to the view hierarchy. Make sure to look up the UIView class in the documentation and understand the variety of ways to add and remove views to the view hierarchy.
A couple things I should warn you about:
* your code above is leaking. You need to review how objective-C properties work. There's lots on this site about it. More than I have time to write about here.
* don't create a rootView property in the case you have here. There already is one in the superclass (UIViewController). It's just 'view'. Use that for saving your root view.
I hope this helps you get started. It can be bewildering at first, but you'll soon get it going! I recommend building and rewriting and rebuilding a lot of sample code before you do your "real" application. The SDK has many great samples.