I am creating an iOS app. On a view controller there are several buttons.
One of them is the AButton, here you have my header file:
#import <UIKit/UIKit.h>
#interface FirstViewController : UIViewController
- (IBAction)Aaction:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *AButton;
#end
I want to open another view controller when AButton is tapped:
#import "FirstViewController.h"
#import "EntradasTableViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (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)Aaction:(id)sender {
EntradasTableViewController *detailViewController =[self.storyboard instantiateViewControllerWithIdentifier:#"entradasViewController"];
detailViewController.categoriaDescription = #"A";
[self.navigationController pushViewController:detailViewController animated:YES];
}
#end
I have declared the StoryBoard identifier as follows:
But after tapping on the button nothing happens, no exception is thrown and the view controller detailViewController is not shown.
Any help is welcome.
NEW IMAGED ADDED:
Here is a screenshot where I am declaring the action for the button in the storyboard:
The problem is that your FirstViewController instance is not in a navigation interface. Therefore when your FirstViewController says self.navigationController, that's nil. Therefore this line:
[self.navigationController pushViewController:detailViewController animated:YES];
...involves sending a message to nil. In Objective-C, sending a message to nil does nothing. So that's why nothing happens.
Related
I have two view controllers in my project ViewController and SecondViewController and my ViewController has a button which performs a popover segue to SecondViewController then in my SecondViewController I have a button which I would like to use to a call a method from ViewController and I assumed it was possible using [self presentingViewController] but that pointer is set to nil so I'm not quite sure how to call a method in the first ViewController inside the SecondViewController after a popover segue.
This is the code for my ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (IBAction)dosegue:(id)sender;
-(void)tobecalledfromseguepopover;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
}
-(void)tobecalledfromseguepopover{
NSLog(#"Called from segue popover");
}
- (IBAction)dosegue:(id)sender {
[self performSegueWithIdentifier:#"segueforpopup" sender:self];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface SecondViewController : UIViewController
- (IBAction)returntocaller:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController()
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)returntocaller:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
ViewController* caller = (ViewController*)[self presentingViewController];
if(caller!=nil){
[caller tobecalledfromseguepopover];
}else{
NSLog(#"nil");
}
}];
}
#end
My UI
So any ideas on how I can call tobecalledfromseguepopover inside SecondViewController after the segue? Also is there a way for SecondViewCOntroller to know it's being called from a segue popover?
The usual thing is a delegate architecture. Give the popover a delegate property and set it to self in your prepareForSegue. Now the popover knows where to find the first view controller.
This is often combined with a protocol so that the popover knows the name of the method to be called without worrying about the class of the first view controller, but that part isn’t crucial, especially in Objective C.
I'd like to trigger a message from viewController to another viewController.
And I coded like below, but viewController didn't call delegate.
I want to call delegate without stroyboard. I just want to send a message to another viewController.
viewController2.h
#protocol ViewController2Delegate;
#interface ViewController2 : UIViewController
#property (nonatomic, weak) id<ViewController2Delegate> delegate;
#end
#protocol ViewController2Delegate <NSObject>
- (void)showSomethingByDelegate;
#end
viewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)buttonPressed:(id)sender {
[self.delegate showSomethingByDelegate];
}
#end
viewController.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
<ViewController2Delegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
ViewController2 *vc2 = [[ViewController2 alloc] init];
vc2.delegate = self;
}
// Below method was not called by delegate.
- (void)showSomethingByDelegate {
NSLog(#"Button Was Pressed!!!");
}
#end
well let me show an example more simple.
File: firstVC.h
/* This define the protocol object,
you can write methods required or optional the diference is when
the protocol is used in a class, xcode show you a yellow warning with required methods
like UITableViewDelegate, UITextFieldDelegate... */
#protocol firstVCDelegate <NSObject>
#required
- (void)didMessageFromOtherViewController: (NSString *)messageStr;
#optional
- (void)didOtherMessageNotRequired: (NSString *)messageStr;
#end
/* This is the definition of first UIViewController */
#interface firstViewController : UIViewController
#end
/* This is the definition of second UIViewController object with
a property that is our protocol 'firstVCDelegate' */
#interface secondViewController : UIViewController
#property (nonatomic, weak) id <firstVCDelegate> firstVCDelegate;
- (void)executeDelegateProcess;
#end
File: firstVC.m
#import "firstVC.h"
#pragma mark - First UIViewController with delegate
#interface firstViewController() <firstVCDelegate>
#end
#implementation firstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Creating the 'secondViewController' object with delegate on this class
secondViewController *svc = [secondViewController new];
// Assign the delegate class
[svc setFirstVCDelegate: self];
// Run the delegate logic
[svc executeDelegateProcess];
}
- (void)didMessageFromOtherViewController:(NSString *)messageStr
{
// Receiving the message from the instance of our protocol in the 'secondViewController' class
NSLog(#"MESSAGE #1: %#", messageStr);
}
- (void)didOtherMessageNotRequired:(NSString *)messageStr
{
// Receiving the message in optional method
NSLog(#"MESSAGE #2: %#", messageStr);
}
#end
#pragma mark - Second UIViewController
#implementation secondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)setFirstVCDelegate:(id<firstVCDelegate>)firstVCDelegate
{
if (firstVCDelegate)
_firstVCDelegate = firstVCDelegate;
}
- (void)executeDelegateProcess
{
// This method is only for demo
// You can execute your delegate in the way you need to use
if (_firstVCDelegate) {
[_firstVCDelegate didMessageFromOtherViewController: #"Hello world, using the required method from secondViewController class"];
[_firstVCDelegate didOtherMessageNotRequired: #"Hello code using the optional method"];
}
}
#end
In your appDelegate.m in the method didFinishLaunchingWithOptions you can put this, and you need to #import "firstVC.h"
self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.autoresizesSubviews = YES;
[self.window makeKeyAndVisible];
[_window setRootViewController: [firstViewController new]];
Execute and see two logs messages, I hope I've helped :)
ViewController2 *vc2 = [[ViewController2 alloc] init];
This line of code is not doing what you think it is, this is creating a NEW instance of ViewController2 and storing it inside the variable vc2. At no point (based on your code) is this variable added to the navigation stack and displayed on screen.
Edit
Also as noticed by Holex, your vc2 variable will be removed from memory after the viewDidLoad is finished as you are not holding onto a reference of it. You would either need to create a property to hold onto it, or push it onto the navigation stack for the navigationController to hold onto it.
There are multiple ways to solve this issue:
Instead of creating a new viewController2, find a reference to the one already displayed on the screen (if it is on the screen).
If its not on the navigation stack, add vc2 to the navigation stack [self.navigationController pushViewController:vc2 animated:YES]; (assuming you have a navigation controller).
If not on the stack, and not intending to use a navigationController, present vc2 modally, such as [self presentViewController:vc2 animated:YES completion:nil];
i have to view controllers .. and i want to pass data from the first to the second view i have this code
for the ViewController.h
#import <UIKit/UIKit.h>
#import "SecondView.h"
#interface ViewController : UIViewController{
SecondView *secondviewData;
IBOutlet UITextField *textfield;
}
#property (nonatomic,retain) SecondView *secondviewData;
-(IBAction)passdata:(id)sender;
#end
for the viewController.m
#import "ViewController.h"
#import "SecondView.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize secondviewData;
-(IBAction)passdata:(id)sender{
SecondView *second= [[SecondView alloc] initWithNibName:nil bundle:nil];
self.secondviewData=second;
secondviewData.passedValue=textfield.text;
[self presentModalViewController:second animated:YES];
}
- (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.
}
#end
for the second view controller which is SecondView.h
#import <UIKit/UIKit.h>
#interface SecondView : UIViewController{
IBOutlet UILabel *label;
NSString *passedValue;
}
#property (nonatomic,retain) NSString *passedValue;
-(IBAction)back:(id)sender;
#end
for the SecondView.m
#import "SecondView.h"
#import "ViewController.h"
#interface SecondView ()
#end
#implementation SecondView
#synthesize passedValue;
-(IBAction)back:(id)sender{
ViewController *vc= [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:vc animated:YES];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
label.text=passedValue;
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
the error I'm having is presentModalViewController deprecated iOS 6 in these 2 lines
[self presentModalViewController:vc animated:YES];
[self presentModalViewController:vc animated:YES];
and when i run it and click on the button it will stop working and displays a blank black page
You can save data in AppDelegate to access it across view controllers in your application. All you have to do is create a shared instance of AppDelegate
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
If you are building for >= iOS 5 then you should be using presentViewController:animated:completion: instead of presentModalViewController:animated:.
Also, the idea of 'back' doesn't usually mean pushing something new. So, this code:
- (IBAction)back:(id)sender {
ViewController *vc= [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:vc animated:YES];
}
should change to:
- (IBAction)back:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
Now, you should look at using a delegate pattern to pass the data back to the originating view controller. And preferably that delegate implementation would include telling the delegate that the second controller is finished and the delegate triggers the dismiss.
See Passing Data between View Controllers
I have a UIViewController calling another view Controller with a defined loadView method. I’ve been trying many options without success to solve the problem of the loadView method not called.
Any help is appreciated.
Thanks.
MArcos
Caller UIViewController
#import "MyAlbumViewController.h"
#interface ViewController : UIViewController
#end
implementation
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidAppear:(BOOL)animated{
UIViewController*albumVC = [[MyAlbumViewController alloc] init];
[self.navigationController pushViewController:albumVC animated:YES];
}
#end
Called UIViewController
#interface MyAlbumViewController : NIToolbarPhotoViewController <NIPhotoAlbumScrollViewDataSource>
#end
Implementation
#import "MyAlbumViewController.h"
#implementation MyAlbumViewController
- (void)loadView{
[super loadView];
self.photoAlbumView.dataSource = self;
// Set the default loading image.
self.photoAlbumView.loadingImage = [UIImage imageWithContentsOfFile:
NIPathForBundleResource(nil, #"NimbusPhotos.bundle/gfx/default.png")];
self.title = NSLocalizedString(#"Loading...", #"Navigation bar title - Loading a photo album");
[self loadAlbumInformation];
}...
The idea of loadView is to completely override the method, and not call super
What you are doing is exactly what the viewDidLoad method is for, it doesn't matter if you loaded it from a nib file or whatever
And I quote from your own post, in your ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
I was pushing view controller with:
[self.navigationController pushViewController:albumVC animated:YES];
I just changed to:
[self presentViewController:albumVC animated:YES completion:nil];
UIViewController Navigation Controller
navigationController The nearest ancestor in the view controller
hierarchy that is a navigation controller. (read-only)
#property(nonatomic, readonly, retain) UINavigationController
*navigationController Discussion If the receiver or one of its ancestors is a child of a navigation controller, this property
contains the owning navigation controller. This property is nil if the
view controller is not embedded inside a navigation controller.
In a view, let's call it firstView I created a secondView as follows and pushed it if certain thing happened in the firstView:
SecondViewController *secondVC = [[secondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:secondVC animated:YES];
[secondVC release];
Now when I'm in the secondView if let say a button is pressed I want to go back to firstView and also pass back a value from secondView to the firstView (let say an integer value of a textfield from secondView to the firstView).
Here is what I tried:
#protocol SecondViewControllerDelegate;
#import <UIKit/UIKit.h>
#import "firstViewController.h"
#interface SecondViewController : UIViewController <UITextFieldDelegate>
{
UITextField *xInput;
id <SecondViewControllerDelegate> delegate;
}
- (IBAction)useXPressed:(UIButton *)sender;
#property (assign) id <SecondViewControllerDelegate> delegate;
#property (retain) IBOutlet UITextField *xInput;
#end
#protocol SecondViewControllerDelegate
- (void)secondViewController:(SecondViewController *)sender xValue:(int)value;
#end
And in the m file
- (IBAction)useXPressed:(UIButton *)sender
{
[self.delegate secondViewController:self xValue:1234]; // 1234 is just for test
}
And then in the firstView I did:
#import "SecondViewController.h"
#interface FirstViewController : UITableViewController <SecondViewControllerDelegate> {
}
#end
And implemented:
- (void) secondViewController:(SecondViewController *)sender xValue:(int)value
{
[self.navigationController popViewControllerAnimated:YES];
}
Now, the problem is for one in FirstViewController I get the warning that "No definition of protocol "SecondViewControllerDelegate" is found, and for two the delegate method (last piece of code above) does not get invoked at all. Can somebody please tell me what's wrong?
After this line
SecondViewController *secondVC = [[secondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
Add
secondVC.delegate = self;
Also instead of
- (void) secondViewController:(SecondViewController *)sender xValue:(int)value
{
[self.navigationController popViewControllerAnimated:YES];
}
You should use
- (void) secondViewController:(SecondViewController *)sender xValue:(int)value
{
[sender popViewControllerAnimated:YES];
}
In FirstViewController .h file :
#import "SecondViewController.h"
#interface FirstViewController : UITableViewController <SecondViewControllerDelegate> {
SecondViewController *secondViewController;
}
#end
In implementation file , where you init SecondViewController instance next line assign self to delegate property :
secondViewController.delegate = self;
Next define delegate method :
- (void)secondViewController:(SecondViewController *)sender xValue:(int)value
{
NSLog ("This is a Second View Controller with value %i",value)
}
For problem 1: The #protocol definition for SecondViewControllerDelegate looks like it's in secondViewController.h; are you sure this file is imported in firstViewController.h? Otherwise it won't know about the protocol.
Problem 2: It might be totally unrelated to problem 1. Are you sure the action is hooked up properly? Can you put a NSLog() call in your useXPressed: to make sure that method is actually getting called when you expect it to?