I have an app, where I making some calculation, and need to transfer result of this calculation to ViewController3 and show the result there. Now I use label in same ViewController2 where I have calculation. Thank you for your help.
ViewController2.h
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController<UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UILabel *gasPrice;
#property (weak, nonatomic) IBOutlet UILabel *gasCarMileage;
#property (weak, nonatomic) IBOutlet UITextField *perGalon;
#property (weak, nonatomic) IBOutlet UITextField *miles;
#property(nonatomic, copy, readonly) NSString *result;
- (IBAction)getIt:(id)sender;
#end
ViewController2.m
#import "ViewController2.h"
#import "ViewController3.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
//Start calculation
- (IBAction)getIt:(id)sender; {
float perGalon = ([_perGalon.text floatValue]);
float miles = ([_miles.text floatValue]);
float mileCost = perGalon / miles;
[self performSegueWithIdentifier:#"viewController3" sender: nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"viewController3"]) {
ViewController3 *viewController3 = [segue destinationViewController];
viewController3.result = [[NSString alloc] initWithFormat: #"Every mile you drive
will cost you $ %f", mileCost];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.perGalon.delegate = self;
self.miles.delegate = self;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
return [textField resignFirstResponder];
}
#end
ViewController3.h
#import <UIKit/UIKit.h>
#interface ViewController3 : UIViewController
#property(nonatomic, copy) NSString *result;
#end
ViewController3.m
#import "ViewController3.h"
#import "ViewController2.h"
#interface ViewController3 ()
#end
#interface ViewController2 ()
#property(nonatomic, copy, readwrite) NSString *result;
#end
#implementation ViewController3
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You can define a string property in View controller 3 which you will set when you push view controller 3 from view controller 2.
ViewController3 interface declaration
#interface ViewController2 ()
#property(nonatomic, copy) NSString *result;
#end
In ViewController 2, you will implement this line at the last of your getIt() method.
[self performSegueWithIdentifier:#"viewController3" sender: nil]
And implement another method called prepareForSegue as follows
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"viewController3"]) {
ViewController3 *viewController3 = [segue destinationViewController];
viewController3.result = "YOUR CALCULATION RESULT HERE"
}
}
Bear in mind, you have to set identifier for view controller 3, go to storyboard and select the view for view controller 3 and On identify inspector, specified Storyboard ID as "viewController3".
Use a protocol,
In ViewController2.h
#protocol ViewController2Delegate;
#property (strong, nonatomic) id<ViewController2Delegate> delegate;
#protocol BexAPIClientDelegate <NSObject>
- (void)ViewController2:(ViewController2 *)vc didCalculateCost:(CGFloat)cost;
#end
Then at the end of the getIt() call the delegate
[self.delegate viewController2:self didCalculateCost:gasCostPerMile];
You need to set ViewController3 to be ViewController2's delegate when you load it. Also you will need to setup ViewController3 to conform to the protocol.
Using the protocol is worth the effort as it will make your code clear and easy to manage.
Retain a string in VC3. While initializing the VC3 object, set the value from VC2. Update the label in VC3(in viewDidLoad method)
Related
Basically, I am now intend to use delegate to pass values between view controllers.
The flow of the view controllers is A -> B -> C using push segue.
When the user does some action in the "C" view controller, how to pass the value BACK to the first view controller, which is "A"?
In my code, "self.delegate" is always nil and the delegate method is never triggered.
Below is the code of the First VC and Third VC:
First VC .m:
#import "ViewController.h"
#import "ThirdViewController.h"
#interface ViewController ()<PassValueProtocal>
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#end
#implementation ViewController
{
ThirdViewController *thirdVC;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void) passValueBack:(NSString *)value
{
NSLog(#"HAHAH");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)segueToSecondVC:(UIButton *)sender
{
thirdVC = [ThirdViewController sharedManager];
thirdVC.delegate = self;
}
#end
Third VC .h:
#import <UIKit/UIKit.h>
#protocol PassValueProtocal <NSObject>
- (void) passValueBack: (NSString *) value;
#end
#interface ThirdViewController : UIViewController
#property (weak, nonatomic) id<PassValueProtocal>delegate;
+ (id) sharedManager;
#end
Third VC .m:
#import "ThirdViewController.h"
#interface ThirdViewController ()
#property (weak, nonatomic) IBOutlet UITextField *myTextField;
#end
#implementation ThirdViewController
+ (id) sharedManager
{
NSLog(#"myDelegate sharedManager");
static ThirdViewController *sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ sharedManager = [[self alloc] init]; });
return sharedManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)passValueAction:(UIButton *)sender
{
NSLog(#"%#", self.delegate);
if ([self.delegate respondsToSelector:#selector(passValueBack:)])
{
[self.delegate passValueBack:self.myTextField.text];
}
}
#end
Your code
- (IBAction)segueToSecondVC:(UIButton *)sender
{
thirdVC = [ThirdViewController sharedManager];
thirdVC.delegate = self;
}
Should not be here. You should implement function prepareForSegue and move this code there. Something like
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
ThirdViewController *thirdVC = (ThirdViewController *)segue.destinationViewController;
thirdVC.delegate = self;
}
I just created a new utility application from the Xcode templates and I have a problem with the - (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller method not being called. When I use the three finger tap on the trackpad to define it, it says that method is defined in MainViewController.m when it is definitely in the protocol of Flip.
MainVC.h
#import "FlipsideViewController.h"
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate, UIPopoverControllerDelegate>
#property (strong, nonatomic) UIPopoverController *flipsidePopoverController;
#property (weak, nonatomic) IBOutlet UIView *backgroundView;
#end
.m
#import "MainViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_backgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"Background.jpg"]];
_backgroundView.contentMode = UIViewContentModeCenter;
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Flipside View Controller
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
//width
if (controller.widthSegmentedControl.selectedSegmentIndex == 0) {
//number of icons
} else {
//icon space
}
NSLog(#"b"); // not called
[self.flipsidePopoverController dismissPopoverAnimated:YES];
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
self.flipsidePopoverController = nil;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAlternate"]) {
[[segue destinationViewController] setDelegate:self];
UIPopoverController *popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
self.flipsidePopoverController = popoverController;
self.flipsidePopoverController.delegate = self;
}
}
- (IBAction)togglePopover:(id)sender
{
if (self.flipsidePopoverController) {
[self.flipsidePopoverController dismissPopoverAnimated:YES];
self.flipsidePopoverController = nil;
} else {
[self performSegueWithIdentifier:#"showAlternate" sender:sender];
}
}
#end
FlipVC.h
#import <UIKit/UIKit.h>
#class FlipsideViewController;
#protocol FlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;
#end
#interface FlipsideViewController : UIViewController
#property (weak, nonatomic) IBOutlet UISegmentedControl *widthSegmentedControl;
#property (weak, nonatomic) IBOutlet UITextField *widthNumberOfIcons;
#property (weak, nonatomic) IBOutlet UITextField *widthIconSpace;
#property (weak, nonatomic) IBOutlet UISegmentedControl *heightSegmentedControl;
#property (weak, nonatomic) IBOutlet UITextField *heightNumberOfIcons;
#property (weak, nonatomic) IBOutlet UITextField *heightIconSpace;
#property (weak, nonatomic) id <FlipsideViewControllerDelegate> delegate;
- (IBAction)done:(id)sender;
#end
.m
#import "FlipsideViewController.h"
#interface FlipsideViewController ()
#end
#implementation FlipsideViewController
- (void)awakeFromNib
{
self.preferredContentSize = CGSizeMake(320.0, 480.0);
[super awakeFromNib];
}
- (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.
}
#pragma mark - Actions
- (IBAction)done:(id)sender
{
NSLog(#"a"); //this is called
[self.delegate flipsideViewControllerDidFinish:self];
}
#end
There are two NSLogs in there, one for the method where the done button gets pressed (a) and one for the one where that didFinish method should be called (b). The problem is that when I press the done button on the Flip controller nothing happens (although "a" gets logged).
I found the problem. I removed the default button bar Info item and replace it with a normal button. The problem is that the segue needs to be anchored to that button and connected to the togglePopover method in the MainViewController.m file.
How to show an UIIimage by clicking on an UIButton inside another UIViewController? I would like to add to the same UIButton the command to add an image to the SecondViewController. Excused my poor question.
myProtocol.h
#import <Foundation/Foundation.h>
#protocol myProtocol <NSObject>
-(UIImage *)transferImage;
#end
ViewController.h
#import "SecondClass.h"
#interface ViewController : UIViewController<myProtocol, UINavigationControllerDelegate>{
UIView *view;
}
#property (nonatomic,retain) UIImageView *imageView;
- (IBAction)sendImage:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#import "myProtocol.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad{
[super viewDidLoad];
_imageView = [[UIImageView alloc]initWithImage:
[UIImage imageNamed:#"VoodooVibe#2x.png"]];
[view addSubview:_imageView];
NSLog(#"I am in VC.m");
}
-(UIImage *)transferImage{
NSLog(#"I am in transferImage");
return _imageView.image;
}
- (IBAction)sendImage:(id)sender {
SecondViewController *secClass = [[SecondViewController alloc]init];
secClass.delegate=self;
[secClass callTransfer];
NSLog(#"I am in sender");
[self.navigationController pushViewController:secClass animated:YES];
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "myProtocol.h"
#import "ViewController.h"
#interface SecondViewController :UIViewController
<myProtocol,UINavigationControllerDelegate> {
UIView *secondView;
IBOutlet UIImageView *myImage;
id <myProtocol> myDelegate;
}
#property (nonatomic,retain) UIImageView *myImage;
#property(nonatomic,assign) id delegate;
-(void)callTransfer;
#end
SecondViewController.m
#import "SecondViewController.h"
#import "ViewController.h"
#import "myProtocol.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize delegate,myImage;
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view.
[secondView addSubview:myImage];
}
-(void)callTransfer{
myImage.image=[delegate performSelector:#selector(transferImage)];
myImage.image=[UIImage imageNamed:#"VoodooVibe#2x.png"];
NSLog(#"%#",myImage.image);
NSLog(#"I am in call transfer");
}
- (void)didReceiveMemoryWarning{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Delegates should normally be used, if you you have a class included inside your UIViewController which will do something and notify you with the delegate method when the specific process has finished. But in this case you would set an UIImage two times. Once by your delegate and a second time by setting an UIImage programmatically.
You shouldn't do anything like calling a method for initializing the UIImage of the second UIViewController from outside. Just call everything inside viewDidLoad and you don't have to care about it, because the UIViewController handles it itself.
You just have to insert an UIImageView inside your SecondViewController and connect it to your header file. then you can access it inside the m. file. I had the problem that I first used a jpg instead of a png, but after changing the suffix everything worked fine.
ViewController.m
- (IBAction)sendImage:(id)sender {
SecondViewController *secClass = [[SecondViewController alloc] init];
[secClass setImageName:#"pic.png"];
[self.navigationController pushViewController:secClass
animated:YES];
}
SecondViewController.h
#interface SecondViewController : UIViewController
#property (strong, nonatomic)NSString *imageName;
#property (weak, nonatomic) IBOutlet UIImageView *myImage;
#end
SecondViewController.m (There are just these two lines)
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[_myImage setImage:[UIImage imageNamed:_imageName]];
}
I am trying to pass data between two view controllers. viewcontroller2 is a delegate of viewcontroller.. note.. i called the delegate property "homie" yes I know this is bad practice but I am just messing around trying to understand the concept.
here is viewcontroller:
#import <UIKit/UIKit.h>
#protocol ViewControllerDelegate <NSObject>
#required
- (void)sendData:(NSString *)theString;
#end
#interface ViewController : UIViewController
#property (nonatomic, assign) id <ViewControllerDelegate> homie;
- (void)doSomething;
- (IBAction)doneText:(id)sender;
#end
implementation:
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (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.
}
-(void)doSomething{
}
- (IBAction)doneText:(id)sender {
UITextField *thisField = sender;
if([_homie respondsToSelector:#selector(sendData:)]){
[_homie sendData:[thisField text]];
}
}
now here is the other view controller implementing the first
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface ViewController2 : UIViewController <ViewControllerDelegate>
- (IBAction)hittingbtn:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *textfield;
#property (strong, nonatomic) ViewController *vc;
#end
implementation:
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
ViewController *theview = [[ViewController alloc]init];
theview.homie = self;
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// DELEGATE METHOD
- (void)sendData:(NSString *)theString{
[_textfield setText:theString];
}
- (IBAction)hittingbtn:(id)sender {
}
#end
in viewdidload I instantiate the first viewcontroller, and set myself as its delegate. im assuming then when that viewcontroller2 runs the code in its method then it will see if its delegate has implemented the delegate method and use that code.. what am i missing here?
Your problem is that you use ViewControllers wrong. You have initialized ViewController
ViewController *theview = [[ViewController alloc]init];
theview.homie = self;
And what next? You haven't assign it to your properties or something. What have you do? It's simple. You have to implement - (void)prepareForSegue:sender:. First of all in your storyboard set segue's identifier. Then do following.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"MySegue"]) {
ViewController *destinationViewController = (ViewController *)[segue destinationViewController];
ViewController.homie = self;
}
}
You need to set the delegate in prepareForSegue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController respondsToSelector:#selector(setHomie)]) {
[segue.destinationViewController setHomie:self];
//or
if ([[segue.destinationViewController isKindOfClass:[ViewController class]]) {
ViewController *destinationViewController = (ViewController *)[segue destinationViewController];
ViewController.homie = self;
}
//or the segue identifier which has already been mentioned
}
I created two pages, called ViewController and SecViewController. In ViewController, which is the first page, with one button and one label. And I set segue on a button to SecViewController, which is the second page.
I am trying to pass the segue identifier to page 2, but this is not success. I test the value passing in page1, the console display
2013-07-05 10:33:54.554 Testing2[1314:c07] 1, (null)
Here is my code:
Anyone can identify which code I typing wrong?
ViewController.h
#import <UIKit/UIKit.h>
#class SecViewController;
#interface ViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *label;
#property (strong, nonatomic) IBOutlet UIButton *button;
#property (strong, nonatomic) SecViewController *view2;
#end
ViewController.m
#import "ViewController.h"
#import "SecViewController.h"
#implementation ViewController
#synthesize label, button, view2;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"1"]){
view2.received = [segue identifier];
NSLog(#"%#, %#", [segue identifier], view2.received);
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[label setText:#"Game Start!"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
SecViewController.h
#import <UIKit/UIKit.h>
#interface SecViewController : UIViewController
#property (strong, nonatomic) id received;
#property (strong, nonatomic) IBOutlet UILabel *label;
#end
SecViewController.m
#import "SecViewController.h"
#implementation SecViewController
#synthesize label;
- (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
You don't have to create a property for the second view controller. You can get it in the prepareForSegue and access the received variable from the second view controller.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"1"]){
SecViewController *vc = [segue destinationViewController];
vc.received = [segue identifier];
NSLog(#"%#, %#", [segue identifier], vc.received);
}
}
if you nslog in the the secondviewcontroller for the value of the received what do you get?
#import "SecViewController.h"
#implementation SecViewController
#synthesize label;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Received %#",self.received);
// 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