I've created a test app to debug this issue so it simply has 2 views, tabs and controllers using storyboard layout in xcode6.
I have a label on tab 1 view and when I hit tab 2, I'd like to change it, e.g. it reads 'foo' now and when I tab back it will say 'bar'.
ViewController.h
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *tab1Label;
#end
ViewController2.m
#import "ViewController.h"
...
- (void) viewDidLoad {
[super viewDidLoad];
ViewController *myVC = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
NSLog(#"%#", myVC.tab1Label.text);
myVC>tab1Label.text = #"bar";
}
It could simply be that I'm calling the other view controller in the wrong way but I'm not sure the right way. The Log output is null when picking up the current text of the label.
Thanks in advance!
UITabBarController *tabBarController = self.tabBarController;
ViewController *myVC = (ViewController *) tabBarController.viewControllers[0]; // 0 = 1st VC
Was the missing link (courtesy of #rcasey on raywenderlich.com)
Related
I'm an iOS developer and I want to create a simple desktop app. I thought the switch would go perfect but it doesn't.
I've created a cocoa app ( from the xCode template ). Now I don't want to use user interface builders and stuff so I wrote my first controller like this:
#interface MainViewController ()
#property (nonatomic, strong) NSTextView *test;
#end
#implementation MainViewController
-(instancetype) init
{
self = [super init];
if(self)
{
NSLog(#"%s", __PRETTY_FUNCTION__);
_test = [[NSTextView alloc] init];
[_test setString:#"DKDDK"];
[self.view addSubview:_test];
[_test mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
}
return self;
}
#interface MainViewController : NSViewController
#end
And I just use the NSWindow that is created by the template:
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
MainViewController * mainView = [[MainViewController alloc] init];
[self.window.contentView addSubview:mainView.view];
mainView.view.frame = ((NSView*)self.window.contentView).bounds;
}
When I run the application it gives me:
[NSViewController loadView] loaded the "(null)" nib but no view was set.
I don't know how to solve this. How can I create an app without nib, just like you do on iOS?
If you aren't loading the view from a NIB then there is little need for a view controller.
Discard the view controller and subclass NSView instead, and set that as the window's content view.
Note: you are making a rod for your own back by not using IB.
I'm trying to make a button take me to a new UIViewController based on the content of a textField, but when I run it and hit the button (with the right condition in the text field to take me to the new UIViewController), the screen blacks out. This is what I wrote in my .h and .m files. Can anyone help me (Im using storyboards)
#interface ViewController : UIViewController
- (IBAction)boton:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *texto;
#end
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize texto;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)boton:(id)sender {
if ([texto.text isEqualToString:#"1"]) {
ViewController2 *vc1=[[ViewController2 alloc]init];
[self presentViewController:vc1 animated:YES completion:nil];
}
}
#end
As you say the screen is blacking out, I expect your viewController is getting initialised without a view.
To initialise with a view hierarchy from a xib(nib) file:
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
where nibName can be nil if it shares it's name with the View Controller, and nibBundle can be nil it the nib is in the main bundle.
i.e....
ViewController2 *vc2;
vc2 = [[ViewController2 alloc] initWithNibName:nil
bundle:nil];
where the xib file is named ViewController2.xib
To initialise from a storyboard:
UIStoryboard *storyboard = self.storyboard;
vc2 = [storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
(you need to set up a viewController in storyboard and give it a matching identifier)
To initialise with neither storyboard or xib, you should override your view controller's - (void)loadView, create a view and assign it to self.view.
Update
In answer to your comment - the UIStoryboard... and ViewController2 *vc2= ... code would go into your button code (in your case it you would replace / adapt the line containing vc1=.... It would look like this:
- (IBAction)boton:(id)sender {
if ([texto.text isEqualToString:#"1"]) {
ViewController2 *vc2;
UIStoryboard *storyboard = self.storyboard;
vc2 = [storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:vc2 animated:YES completion:nil];
}
You will need to have created a storyboard scene in your storyboard with a viewController whose custom class is ViewController2 and identifier is "ViewController2". The identifier name is arbitrary, but must match the identifier string you use in your code.
As you are using storyboards, an alternative way to do this is to create a modal segue from the 'ViewController' scene to a 'ViewController2' scene, give it an identifier, and use performSegueWithIdentifier in your button method.
I am using a single view application template in xcode. I created the first view controller, and then added another with a new .m and .h and xib.
I can click a button IBAction, and get to my second view, however the code I am using for the "back" button wont take me back to my first view, everything crashes. I have included my code which seems to follow the tutorial I was using. Additionally I just control clicked my button and dragged the line to my IBAction in the .h to hook in the secondViewController buttons, which is what I did on the first view controller and it seems to work there.
If anyone can help that would be great!
//from my first view controller .h which works
-(IBAction) buttonPressedPayTable: (id) sender;
//from my first view controller.m which also works and gets me to the second view
-(IBAction) buttonPressedPayTable: (id) sender
{
SecondViewController *payTableView = [[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil];
[self.view addSubview:payTableView.view];
}
//from my second view controller .h that will not get me back to the first view without crashing
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
{
}
-(IBAction) back: (id)sender;
#end
//from my second view controller .m which doesn't seem to work
#import "SecondViewController.h"
#implementation SecondViewController
-(IBAction) back: (id)sender
{
[self.view removeFromSuperview];
}
#end
use UINavigation controller
[self.navigationController popViewControllerAnimated:YES];
You might be better off using modal views. So instead of addSubView use:
[payTableView setModalPresentationStyle:UIModalPresentationFullScreen];
[payTableView setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentModalViewController:payTableView animated:YES];
Then on the seconViewController back method:
[self dismissModalViewControllerAnimated:YES];
You can change the ModalTransitionStyle to the few that apple gives you :D
Hope this helps
You can use a navigation method for switching from one view controller to the other.
See the apple docs about view controllers
Don't add your second ViewController as a subview of the view.
Use a UINavigationController to add the new UIViewController to the view stack using [self.navigationController pushViewController:payTableView animated:YES];
Then you can either use the nav controllers back button, or use your own button with the code [self.navigationController popViewControllerAnimated:YES];
Alternately, you can use Storyboards and use a simple segue.
[payTableView.view removeFromSuperview];
i think you are removing the whole view .that is why app is crashing
You need to use delegate here:
in .h of first view declare a member variable :
#interface FirstViewControllerClassName: UIViewController
{
SecondViewController *payTableView;
}
#property (nonatomic, retain) SecondViewController *payTableView;
in .m :
#synthesize payTableView;
-(IBAction) buttonPressedPayTable: (id) sender
{
if (!payTableView)
payTableView = [[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil];
payTableView.delegate = self;
payTableView.isFinishedSelector = #selector(removeView);
[self.view addSubview:payTableView.view];
}
- (void)removeView
{
[payTableView.view removeFromSuperview];
[payTableView release];
payTableView = nil;
}
//Just declare a member variable delegate in secondviewcontroller like:
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
{
id delegate;
SEL isFinishedSelector;
}
#property (nonatomic, assign) id delegate;
#property (nonatomic, assign) SEL isFinishedSelector;
-(IBAction) back: (id)sender;
#end
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize delegate;
#synthesize isFinishedSelector;
-(IBAction) back: (id)sender
{
if ([self.delegate respondsToSelector:isFinishedSelector])
[self.delegate performSelector:isFinishedSelector];
}
#end
I know similiar questions have been asked before, but please bear with me as I am totally new at Objective C (have good knowledge on C).
My case is that I have a tab bar controller with two windows. When I press a button in "second" I change a variable changeName. I want to use the value of changeName in my "first" view controller but stumbled on to some problems:
To reach the other viewcontroller I found this from SO (unfortunately I forgot where):
-(NSString *)newName{
// Create a UIStoryboard object of "MainStoryBoard_iPhone" named storyboard
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:(NSString *)#"MainStoryBoard_iPhone" bundle:(NSBundle *)nil];
// Create a UIViewController object of the wanted element from MainStoryBoard_iPhone
UIViewController *secondview = [storyboard instantiateViewControllerWithIdentifier:(NSString *)#"secondBoard"];
return secondview.changeName;
}
Which I have in my first.m. MainStoryBoard_iPhone is the name of the .xib/storyboard-file.
but no. Error says
Property 'changeName' not found on object of type 'UIViewController *'
In my second.h I have
#property (readwrite, retain) NSString *changeName;
and in second.m
#synthesize changeName;
All help is appreciated, but please keep in mind that I have only used OOP for two days.
Thank you all in advance
EDIT: And what input should I have here?
- (void)viewDidLoad
{
[super viewDidLoad];
mylabel.text = Name; // or [mylabel.text Name] or something?
}
You need to cast the view controller returned to your customized second view controller (as UIViewController does not have the property changeName).
So do the following :
// Create a UIViewController object of the wanted element from MainStoryBoard_iPhone
SecondViewController *secondview = (SecondViewController *)[storyboard instantiateViewControllerWithIdentifier:(NSString *)#"secondBoard"];
I assume SecondViewController is the name of your second controller.
In my case I wanted to pass a string from FirstViewController to set a text field in SecondViewController, so:
1- In SecondViewController.h
#property (strong, nonatomic) IBOutlet UITextField *someTextField;// this is linked to a UITextField
2- In FirstViewController.m:
#import "SecondViewController.h"
3- I will do this after a press of a button in the FirstViewController:
SecondViewController *SecondView = [[SecondViewController alloc]
initWithNibName:#"SecondViewController" bundle:nil];
//set fields values
SecondView.someTextField.text = #"HeLLO from First";
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController: SecondView];
//show AdView
[self.navigationController presentViewController:nav animated:YES completion:nil];
4- This is it!
5- There is a case, if I'm in FirstViewController and wanted to set a string property in the SecondViewController with the same way, the string won't get the value till you press a some kinda button in SecondViewController, it won't get it like in viewDidLoad for example! don't know why.
I'm trying to create a UI whereby I have a SplitView with the Details area containing a TabBarController. The TabBarController will show 3 different types of detail for the item selected in the RootViewController of the SplitView.
So far, I've got the TabBar showing the SPlitView by doing the following;
1) Created a new SplitView based app.
2) Created a new TabBar based app
3) Copy the .xib, .h and .m files for the FirstView and SecondView controllers from the TabBar app into the SplitView app.
4) Added the following to my application delegate header file;
#class RootViewController;
#class DetailViewController;
#class FirstViewController;
#class SecondViewController;
#interface SplitViewTemplateAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UISplitViewController *splitViewController;
UITabBarController *tabBarController;
RootViewController *rootViewController;
DetailViewController *detailViewController;
FirstViewController *firstViewController;
SecondViewController *secondViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UISplitViewController *splitViewController;
#property (nonatomic, retain) IBOutlet RootViewController *rootViewController;
#property (nonatomic, retain) IBOutlet DetailViewController *detailViewController;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#property (nonatomic, retain) IBOutlet FirstViewController *firstViewController;
#property (nonatomic, retain) IBOutlet SecondViewController *secondViewController;
5) Opened up MainWindow.xib in IB and changed the class on the DetailsView to UITabController
6) Added the following code to my application delegate module file;
#import "FirstViewController.h"
#synthesize window, splitViewController, rootViewController, detailViewController, tabBarController, firstViewController, secondViewController;
-(void) makeTabBarController {
NSMutableArray *controllers = [NSMutableArray arrayWithArray:splitViewController.viewControllers];
int index = 0;
for (UIViewController *controller in splitViewController.viewControllers) {
if (index == 1) {
//NSLog(#"Index is: %#", index);
//NSLog(#"Controller name is: %#", controller.title);
UINavigationController *localNavController;
tabBarController = [[UITabBarController alloc] init];
NSMutableArray *localViewControllersArray = [[NSMutableArray alloc] initWithCapacity:2];
firstViewController = [[FirstViewController alloc] initWithNibName:#"FirstView" bundle:nil];
localNavController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
localNavController.tabBarItem.title = #"First Tab";
[firstViewController release];
[localViewControllersArray addObject:localNavController];
[localNavController release]; // Retained by above array
secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondView" bundle:nil];
localNavController = [[UINavigationController alloc] initWithRootViewController:secondViewController];
localNavController.tabBarItem.title = #"Second Tab";
[secondViewController release];
[localViewControllersArray addObject:localNavController];
[localNavController release]; // Retained by above array
tabBarController.viewControllers = localViewControllersArray;
[localViewControllersArray release]; // Retained thru above setter
//tabBarController.delegate = splitViewController;
[controllers replaceObjectAtIndex:index withObject:tabBarController];
}
index++;
}
splitViewController.viewControllers = controllers;
}
7) Added the following to the didFinishLaunchingWithOptions method;
[self makeTabBarController];
So now I get an out of the box SplitView with a tab bar controller on the right with two tabs in it. The tabs work for switching between the views.
A couple of things that I am now struggling with are;
The button to fire the Popover is missing, do I need to add this to each tab view?
How do I hook the RootViewController with the TabBarController so that details for the selected item is shown?
not sure if you're still looking for an answer for this. I ran into a very similar issue with the question about multiple detail views. In the end, I found and used this solution from the apple developer site:
SubstitutableDetailViewController
Their solution is very straightforward to implement and very understandable.
With regards to the second part of your question, you could have the TabBarController Delegate inform the view on the left hand side of the split view who the current detail view is. It could then use that information to provide updates to the proper view.