I have three navigation buttons in a view controller, two of which I process locally and one which launches an edit view controller. I have created a segue from the body of the first UITableView to the Navigation Controller of the destination view controller (the edit view controller).
The button works fine (i.e. launches the edit view) but it doesn't receive the string I send to it. Could someone please help. I have tried all of the suggestions given to other related questions but cannot seem to fix this. Following is the related code.
Source controller.h:
#import <UIKit/UIKit.h>
#import "EQHorseAddViewController.h"
#import "EQDatabase.h"
#interface EQHorseDetailViewController : UITableViewController
#property (strong, nonatomic) EQHorseAddViewController *addViewController;
Source controller.m:
#import "EQHorseDetailViewController.h"
#interface EQHorseDetailViewController ()
#end
#implementation EQHorseDetailViewController
#synthesize addViewController;
-(void)viewDidLoad
{
[super viewDidLoad];
UIBarButtonItem *deleteItem= [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemTrash
target:self
action:#selector(deleteHorse:)];
UIBarButtonItem *editItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self
action:#selector(editHorse:)];
NSArray *actionButtonItems = [[NSArray alloc] initWithObjects:deleteItem, editItem,
nil];
self.navigationItem.rightBarButtonItems = actionButtonItems;
}
-(void)editHorse:(id)sender
{
NSLog(#"EditingHorse");
self.addViewController= [[EQHorseAddViewController alloc] init];
addViewController.resultSegue = #"Edit Horse Details";
[self performSegueWithIdentifier:#"EditHorseDetails" sender: self];
}
Destination View Controller.h:
#import <UIKit/UIKit.h>
#import "EQHorseDetailsInfo.h"
#import "EQDatabase.h"
#class EQHorseAddViewController;
#protocol EQHorseAddViewControllerDelegate <NSObject>
- (void) eqHorseAddViewControllerDidCancel:(EQHorseAddViewController *)controller;
- (void)eqHorseAddViewControllerDidSave: (EQHorseAddViewController *)controller;
#end
#interface EQHorseAddViewController : UITableViewController
<EQHorseAddViewControllerDelegate>
#property (strong, nonatomic) EQHorseAddViewController *addViewController;
#property (nonatomic, weak) id <EQHorseAddViewControllerDelegate> delegate;
#property (strong,nonatomic) NSString *resultSegue;
Destination View Controller.m
#import "EQHorseAddViewController.h"
#import "EQDatabase.h"
#import "EQHorseDetailsInfo.h"
#interface EQHorseAddViewController ()
#end
#implementation EQHorseAddViewController
#synthesize resultSegue;
- (void)viewDidLoad
{
NSLog(#"resultSegue %#",resultSegue);
}
Thanking you in advance.
It looks like you're referring to the code in editHorse:, which allocates an EQHorseAddViewController and sets a property on it. The problem with that code is that the view controller it allocates bears no relation to the vc destination of the segue. That method simply creates a vc and then instantly discards it.
Remove the allocation and instead implement prepareForSegue:. The segue object passed to that method will have a property called destinationViewController. That's the view controller that's about to be pushed onto the navigation. That's the one on which you should set the resultSegue property.
-(void)editHorse:(id)sender
{
NSLog(#"EditingHorse");
[self performSegueWithIdentifier:#"EditHorseDetails" sender: self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"EditHorseDetails"]) {
EQHorseAddViewController *vc = segue.destinationViewController;
vc.resultSegue = #"Edit Horse Details";
}
}
You need to define the new controller as follows:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
EQHorseAddViewController *ivc = [storyboard instantiateViewControllerWithIdentifier:#"EditHorseDetails"];
ivc.resultSegue = #"Edit Horse Details";
Perhaps you'll need this method too
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"EditHorseDetails"]) {
// Get destination view
EQHorseAddViewController *vc = [segue destinationViewController];
vc.resultSegue = #"Edit Horse Details";
}
}
-(void)editHorse:(id)sender
{
NSLog(#"EditingHorse");
resultSegue = #"Edit Horse Details";
[self performSegueWithIdentifier:#"EditHorseDetails" sender: self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController *navigationController = segue.destinationViewController;
EQHorseAddViewController *addViewController = [navigationController viewControllers]
[0];
// Get destination view
NSLog(#"ResultSegue in Prepare - %#",resultSegue);
addViewController.resultSegue = #"Edit Horse Details";
}
Related
I am at a loss as to how to pass a selected image in one view controller to a tab bar controller using a segue, i keep on getting "unrecognized selector sent to instance ...". Here is my prepare for segue in a ViewController3 :
if ([[segue identifier]isEqualToString:#"tabbarGo"]) {
UITabBarController *tabar=segue.destinationViewController;
UINavigationController *navController = [tabar.viewControllers objectAtIndex:1];
ViewController5 *fifthView=[navController.viewControllers objectAtIndex:0];
fifthView.theImage = selectedImage.image;
[tabar setSelectedIndex:1];
}
i have imported ViewController5 into ViewController3 as 5 is the tab bar controller and the m file for viewcontroller5 is as follows :
#import <UIKit/UIKit.h>
#import "ViewController5.h"
#import "ViewController3.h"
#interface ViewController5 ()
#end
#implementation ViewController5
#synthesize theImage;
-(void)setImage:(UIImage *)image
{
}
- (void)viewDidLoad {
[super viewDidLoad];
[_imageView setImage:theImage];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I do not understand what i am doing wrong and have gone through most of the posts, or should i go through a "NSUserDefaults *prefs" approach to this ?
Any help appreciated and thanks.
ok got it to work to send an image to a tab bar with navigation controller by adding one line of code, i was forgetting to specify the NSString value of the segue so here is the final full code for "prepare for segue" :
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString * segueIdentifier = [segue identifier];
UITabBarController *tabar=segue.destinationViewController;
UINavigationController *navController = [tabar.viewControllers objectAtIndex:1];
ViewController5 *fifthView=[navController.viewControllers objectAtIndex:0];
fifthView.theImage = selectedImage.image;
[tabar setSelectedIndex:1];
}
I'm new to iOS and Its developing.i have read Xcode old style passing data between view controllers.there i have seen lot of things going with xib files.please find below the code i have used to pass data in-between ViewControllers.but there in customelink(please find DetailViewController.m)there I'm getting Null value.please help me to get String value there.and kind enough to explain what are the mistakes I've done here.
EssentialInfoController.h
#import <UIKit/UIKit.h>
#import "DetailViewController.h"
#interface Essentialinfocontroller : UIViewController
#end
EssentialInfoController.m
#import "Essentialinfocontroller.h"
#interface Essentialinfocontroller ()
#end
#implementation Essentialinfocontroller
- (void)viewDidLoad
{
[super viewDidLoad];
DetailViewController * customelink= [DetailViewController alloc ];
customelink.link=#"https://www.facebook.com";
}
#end
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController
#property(weak,nonatomic)NSString * link;
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#property(nonatomic,weak)NSString *customelink;
#end
#implementation DetailViewController
#synthesize link;
#synthesize customelink;
- (void)viewDidLoad
{
[super viewDidLoad];
self.customelink=self.link;
NSLog(#"link--> %#",customelink);// here 2014-07-06 21:21:51.469 WADTourisum[880:60b] link--> (null)
}
#end
DetailViewController * customelink= [DetailViewController alloc ];
should be
DetailViewController * customelink= [[DetailViewController alloc ] init];
and
#property(weak,nonatomic)NSString * link;
should be
#property(strong,nonatomic)NSString * link;
and log it
NSLog(#"link--> %#",self.link);
you don't need this one
#property(nonatomic,weak)NSString *customelink;
if you use storyboard and segue then you have to implement
-(void)prepareForSegue method.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
assume that you got a button to move from essentialVC to detailVC, in you IBAction, call this method:
[self performSegueWithIdentifier:#"YOUR_SEGUE_NAME_HERE" sender:self];
this is just a brief answer. I suggest you read about UINavigationController first, it's much easier to use compared to segue, IMHO.
I tried many custom delegate examples in my code to send data from view B back to parent view A. Why am I getting NULL? There should be something I am missing. Please help. How can I call setupDate to receive (NSDate *)setAlarmDate in Parent view?
Parent view
#import "SetupViewController.h"
#interface ViewController : UIViewController <SetupViewControllerDelegate> {
NSTimer *timer;
}
#end
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"setupview"]) {
NSLog(#"prepare for segue");
SetupViewController *svc = [[SetupViewController alloc] init];
svc.delegate = self;
-(void)setupDate:(NSDate *)setAlarmDate{
NSLog(#"Hey Hey");
NSLog(#"%#", setAlarmDate);
}
#end
View B
#protocol SetupViewControllerDelegate <NSObject>
#required
-(void)setupDate:(NSDate *)setAlarmDate;
#end
#interface SetupViewController : UIViewController
#property (nonatomic, strong) id <SetupViewControllerDelegate> delegate;
//IB
#property (weak, nonatomic) IBOutlet UIDatePicker *pDatePicker;
#end
.m
#import "SetupViewController.h"
#import "ViewController.h"
#implementation SetupViewController
-(void)viewWillDisappear:(BOOL)animated{
NSDate *date = [self.pDatePicker date];
[[self delegate] setupDate:date];
}
#end
You should access the UIViewController using the segue's destinationViewController property instead of allocating an instance of your own, which is why your alarmDate = NULL.
E.g.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"setupview"])
{
NSLog(#"prepare for segue");
SetupViewController *svc = [segue destinationViewController];
svc.delegate = self;
}
}
Also, as #Neru mentioned your delegate should be qualified as weak and not strong. The reason for this is because you will cause a retain cycle if you do not explicitly set the delegate = nil in the dealloc method.
Using a storyboard I've set up two different view controllers (A&B) where one of them (B) have a UITextView.
How can I access and change the text in the textview from View Controller A?
The code below doesn't give any errors but the text isn't set, even though the function is called correctly.
If I run [self.desc setText:text]; inside viewDidLoad in ViewControllerB it works.
ViewControllerA.h
#interface ViewControllerA : UIViewController
{
}
#end
ViewControllerA.m
#import "ViewControllerA.h"
#import "ViewControllerB.h"
#interface ViewControllerA ()
#end
#implementation ViewControllerA
- (void)viewDidLoad
{
[super viewDidLoad];
ViewControllerB *bInstance = [[ViewControllerB alloc] init];
[bInstance setDescription:#"this is some new text";
}
#end
ViewControllerB.h
#interface ViewControllerB : UIViewController
{
UITextView *desc;
}
- (void)setDescription:(NSString *) text;
#property (nonatomic, retain) IBOutlet UITextView *desc;
#end
ViewControllerB.m
#import "ViewControllerB.h"
#interface ViewControllerB ()
#end
#implementation ViewControllerB
#synthesize desc;
- (void)setDescription:(NSString *)text{
NSLog(#"called!");
[self.desc setText:text];
}
#end
You should not manipulate another view controller's views, ever. It is bad design in general, and often doesn't work at all (as you've discovered.)
Instead, set up a string property in your second view controller. Set that (in prepareForSegue, if you're using storyboards.)
Then, in your second view controller's viewWillAppear, put the string into the text field.
Do the following:
#interface ViewControllerA : UIViewController
{
UITextView *desc;
#public
ViewControllerB objB;
}
When you launch:
ObjectOfAToLaunch.objB = ObjectOfBToLaunch;
In view did load
- (void)viewDidLoad
{
[super viewDidLoad];
[Objb setDescription:#"this is some new text"];
}
Good Luck.
You can implement prepareForSegue method in the controller that launch A and B.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
UIViewController *vc = [segue destinationViewController];
if ([vc isKindOfClass:ViewControllerB])
{
ObjB = vc; // ObjB is a public member you must declare in interface
if (ObjA!=nil)vc->ObjA = ObjB;
}
if ([vc isKindOfClass:ViewControllerA])
{
ObjA = vc; // ObjA is a public member you must declare in interface
if (ObjB!=nil)vc->ObjA = ObjB;
}
}
}
Good Luck.
bInstance is another instance of the class. not the same one.
I have a ViewController1 with a UILabel that can present a ViewController2 with a Modal Segue. I have a UITextField in ViewController2 that I need to access from ViewController1 so I can set my UILabel with the collected text.
I've tried working with the prepareForSegue without success. What should I do?
EDIT:
I'm using a Delegate, but I'm doing something wrong. Here's the code I'm using in ViewController2.h:
#class ViewController2;
#protocol VCProtocol
-(void)setName:(NSString *)name;
#end
#interface ViewController2 : UIViewController
#property (nonatomic, weak) id<VCProtocol> delegate;
#property (strong, nonatomic) IBOutlet UITextField *nameField;
- (IBAction)setButton:(id)sender
#end
ViewController2.m
-(IBAction)setButton:(id)sender
{
[self.delegate setName:nameField.text];
}
I conform to VCProtocol in my ViewController1.h. Then, in my ViewController1.m, I have this code:
- (void)setName:(NSString *)name
{
self.firstSignatureNameLabel.text = name;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqual:#"Sign"])
{
ViewController2 *VC = [segue destinationViewController];
VC.delegate = self;
}
}
You can create a protocol and set VC1 as delegate of VC2, and using prepareForSegue to set VC1 as VC2's delegate should work. I know that you said it didn't work, but I can't see why. Have a try with this :
Give an identifier to your segue (on storyboard), and implement prepareForSegue as shown below :
VC2Delegate.h :
#protocol VC2Delegate
- (void)updateLabel:(NSString *)text;
#end
VC1.h :
#import "VC2Delegate.h"
#interface VC1 : UIViewController <VC2Delegate>
// All your stuff
#end
VC1.m :
- (void)updateLabel:(NSString *)text {
[_label setText:text];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"YourSegueIdentifier"]) {
VC2 * vc = [segue destinationViewController];
[vc2 setDelegate:self];
}
}
VC2.h :
#import "VC2Delegate.h"
#interface VC2 : UIViewController
#property (weak, nonatomic) id<VC2Delegate>delegate;
#end
VC2.m
- (void)textWasUpdated { // or whatever method where you detect the text has been changed
if (_delegate)
[_delegate updateLabel:[_textView text]];
}
Tell me if it works. Else, is prepareForSegue even been called ?
EDIT : Updated my answer (wasn't exactly what you needed).
But as you say it doesn't work :
Is prepareForSegue called ?
If so, is the delegate method called ?
If the delegate method isn't called, check that delegate is not nil.
You might want to remove the segue, and present it modally by yourself, using presentViewController:animated:completion:, like that :
- (IBAction)buttonWasTapped {
static NSString * const idModalView = #"modalView";
static NSString * const storyBoardName = #"MainStoryBoard"
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:storyBoardName bundle:nil];
VC2 * vc = [storyboard instantiateViewControllerWithIdentifier:idModalView];
[vc setDelegate:self];
[self.navigationController presentViewController:vc2 animated:YES completion:nil];
}
When I ran into this problem, I chose the singleton approach and it works.