iOS dev - UINavigationController: send data backwards to 2nd parent view - ios

so, I need to send data backwards when poping two views. I tried using protocol, so this is part of my code:
RootViewController.h
#import <UIKit/UIKit.h>
#import "ThirdViewController.h"
#class SecondViewController;
#interface RootViewController : UIViewController <PassInt>
#property (strong, nonatomic) SecondViewController *secondViewController;
#property (strong, nonatomic) ThirdViewController *thirdViewController;
#property (nonatomic) int intNumber;
#end
RootViewController.m
#import "RootViewController.h"
#import "SecondViewController.h"
#implementation RootViewController
#synthesize secondViewController = _secondViewController;
#synthesize thirdViewController = _thirdViewController;
#synthesize intNumber = _intNumber;
- (void)setIntNumber:(int)number{
_intNumber = number;
}
#pragma mark - View lifecycle
- (void)viewWillAppear:(BOOL)animated {
if(!_thirdViewController){
_thirdViewController = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:[NSBundle mainBundle]];
}
if(!_secondViewController){
_secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:[NSBundle mainBundle]];
self.secondViewController.thirdViewController = self.thirdViewController;
}
[self.navigationController pushViewController:self.secondViewController animated:YES];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#class ThirdViewController;
#interface SecondViewController : UIViewController
#property (strong, nonatomic) ThirdViewController *thirdViewController;
#end
SecondViewController.m
#import "SecondViewController.h"
#import "ThirdViewController.h"
#implementation SecondViewController
#synthesize thirdViewController = _thirdViewController;
...
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
[self.navigationController pushViewController:self.userPreferencesViewController animated:YES];
}
#end
ThirdViewController.h
#import <UIKit/UIKit.h>
#protocol PassInt <NSObject>
#required
- (void) setIntNumber:(int)number;
#end
#interface ThirdViewController : UIViewController{
id <PassInt> delegate;
}
#property (retain) id delegate;
- (IBAction)saveChanges;
#end
ThirdViewController.m
#import "ThirdViewController.h"
#implementation ThirdViewController
- (IBAction)saveChanges{
int someInt = 3;
[[self delegate] setIntNumber:someInt];
UINavigationController *tempNavigationController = self.navigationController;
[tempNavigationController popViewControllerAnimated:NO];
[tempNavigationController popViewControllerAnimated:NO];
}
...
#end
I would appreciate any help!

In the UINavigationController reference check the property call :
#property(nonatomic, copy) NSArray *viewControllers
Discussion
The root view controller is at index 0 in the array, the back view controller is at index n-2, and the top controller is at index n-1, where n is the number of items in the array.
That could give you a handle to the rootViewController.
Would that be a good solution for you?
There is other ways. But from your comment I think that could be a match.
[[self.navigationController viewControllers] objectAtIndex:0].someProerty;

Another method could be to use NSNotifications. Have the RootViewController resgister as an observer for a notification posted by the ThirdViewController. Then in the userInfo dictionary of the notification posted by the ThirdViewController, you pass someInt as an NSNumber.
This provides sufficient abstraction because your ThirdViewController doesn't need to know what kind of object requires the information, it is just posting it so interested observers know about it.
Good Luck

You're never assigning anything to the delegate member of your ThirdViewController in the code you posted. Also, delegates should usually be assign, not retain.

Related

Passing data to method in Tab Bar View Controller Before ViewDidLoad

I have two view controllers used in a Tab Bar Controller: FirstViewController and SecondViewController. I'm trying to call a method in the SecondViewController from the FirstViewController, but do this before the SecondViewController is loaded by selecting the Second Tab. Is this possible? I've tried notifications and delegates and can't seem to get it to work, unless I select the SecondViewController and run ViewDidLoad first, and then call it from the FirstViewController.
This is in objective-c and I'm trying to call setAutoModeTimer() in the SecondViewController.
Here is my code:
FirstViewController.h
#import <UIKit/UIKit.h>
#protocol FirstViewControllerDelegate <NSObject>
- (void) setAutoModeTimer;
#end
#interface FirstViewController : UIViewController
#property (nonatomic,weak) id <FirstViewControllerDelegate> delegate;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
SecondViewController * myViewController = [[SecondViewController alloc] init];
[myViewController view];
// Do any additional setup after loading the view, typically from a nib.
}
//- (void)loadView{[self.tabBarController.viewControllers makeObjectsPerformSelector:#selector(view)];}
- (IBAction)startTimerButtonPressed:(id)sender {
[self.delegate setAutoModeTimer];
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController
#end
SecondViewController.m
#import "SecondViewController.h"
#import "FirstViewController.h"
#interface SecondViewController () <FirstViewControllerDelegate>
#end
#implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
FirstViewController *firstVC = [self.storyboard instantiateViewControllerWithIdentifier:#"FirstViewController"];
firstVC.delegate = self;
}
- (void) setAutoModeTimer
{
NSLog(#"Timer has started");
}
#end
You don't need to keep references in each view controller for another one. What are you doing is creating new instances of UIViewControllers in each view controller.
FirstViewController *firstVC = [self.storyboard instantiateViewControllerWithIdentifier:#"FirstViewController"];
firstVC.delegate = self;
After viewDidLoad will be finished firstVC instance will be released.
Because you created a local var. It is not the same viewController you have in tabBar.
You need to setup connection between view controllers once.
It can be done by setup your UITabBarController programmatically, not in stroryboard.
You can setup viewControllers of UITabBarController once, and setup connections between them.
#import "SecondViewController.h"
#import "FirstViewController.h"
#implementation MainTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *listOfViewControllers = [[NSMutableArray alloc] init];
FirstViewController *firstVC = [self.storyboard instantiateViewControllerWithIdentifier:#"FirstViewController"];
SecondViewController * secondVC = [[SecondViewController alloc] init];
firstVC.delegate = secondVC;
[listOfViewControllers addObject:firstVC];
[listOfViewControllers addObject:secondVC];
[self setViewControllers:listOfViewControllers
animated:YES];
}

Passing string from second view controller to first controller

I am trying to send string from Second VC to First VC. I have assigned delegate to first VC and given protocol in second VC but I don't see the method in First VC is being called when Second VC sends some data.
Code
First VC
FirstViewController.h
#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#interface FirstViewController : UIViewController <cellDelegate>
#end
FirstViewController.m
- (void)printString:(NSString *)string{
NSLog(#"Received string: %#",string);
}
SecondViewController.h
#protocol cellDelegate <NSObject>
- (void)printString:(NSString *)string{
#end
#interface SecondViewController : UIViewController
#property (nonatomic, weak) id <cellDelegate> delegate;
#end
SecondViewController.m
- (IBAction)buttonPressed:(id)sender {
if ([self.delegate respondsToSelector:#selector(printString:)]) {
[self.delegate printString:#"arrow"]];
}
}
Any help is greatly appreciated.
You forgot to do
SecondViewcontroller *vc;
vc.delegate=self;
On first view controller
Maybe you just forgot to assign your secondViewController.delegate to self.
1- In first viewController, before pushing secondViewController, with that SecondViewController instance do:
secondViewController.delegate = self;
I can not comment, so if this does not work out just let me know or share more code.
When you navigate from one VC to Second VC you can set the delegate.
SecondViewcontroller *secondVC = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondViewcontroller"];
secondVC.delegate = self;
[self.navigationController pushViewController:secondVC animated:YES];
This code writes on FirstViewController. Hope it helps you.

Not able to access delegate method from presented view controller

Delegate declaration
// FolderListViewController.h
#import <UIKit/UIKit.h>
#import "Folder.h"
#protocol FolderSelectionDelegate <NSObject>
#required
- (void)setFolder:(Folder *)folder;
#end
#interface FolderListViewController : UITableViewController
#property (nonatomic, assign) id<FolderSelectionDelegate> delegate;
- (IBAction)showDashboard:(id)sender;
#end
Delegate is called from didSelectRowAtIndexPath:
// FolderListViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.delegate setFolder:dataSource[indexPath.row]];
}
The VC that should be receiving the message
#import <UIKit/UIKit.h>
#import "FolderListViewController.h"
#import "Folder.h"
#interface ProjectListViewController : UITableViewController <FolderSelectionDelegate, UISplitViewControllerDelegate, UISearchBarDelegate, UINavigationControllerDelegate>
#property (nonatomic,retain)UIActivityIndicatorView *activityIndicatorObject;
#property (nonatomic, copy)Folder *folder;
-(void)loadProjects:(Folder*)folder;
#end
Action that presents the VC
- (void)foldersButtonTapped {
UINavigationController *vc = [[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"FolderListNavController"];
vc.delegate = self;
[self presentViewController:vc animated:YES completion:nil];
}
Delegate method implementation
- (void)setFolder:(Folder *)folder {
_folder = folder;
[self loadProjects:folder];
}
I have read through multiple threads on here and haven't had any luck. At first, I didn't have the reference to ProjectListVC setup when presenting the FolderListVC (ie, vc.delegate = self). That doesn't seem to be the problem here though. I am working on an app that was built for iPad and scaling it to work across all devices. The implementation as it is here works (it's setup as a split view controller). Any help would be greatly appreciated
I think that UINavigationcontroller is creating problem as it is not setting the FolderListViewController delegate . Can You try like this.
FolderListViewController *vc=[self.storyboard instantiateViewControllerWithIdentifier:#"FolderListViewController"];
vc.delegate=self; // protocol listener
[self.navigationController pushViewController:vc animated:YES];

Declaring UIViewController variable property on another ViewController with Swift

I am a newbie to Swift. I have started a new project with Swift. I am trying to add SecondViewcontroller view as a subview to the FirstViewController. What i am looking is to declare the SecondViewController property for the FirstViewController. Can anyone please suggest the Swift version of the below code
FirstViewController.h
#interface FirstViewController : UIViewController {
IBOutlet UIView *listContainerView;
}
#property (nonatomic, strong) SecondViewController *secondVC;
#end
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIStoryboard *mainStoryBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.secondVC = (SecondViewController *)[mainStoryBoard instantiateViewControllerWithIdentifier:#"SecondViewController"];
if (![self.secondVC.view isDescendantOfView:self.view]) {
[self addChildViewController:self.secondVC];
self.secondVC.view.frame = CGRectMake(0, 0, listContainerView.frame.size.width, listContainerView.frame.size.height);
[listContainerView addSubview:self.secondVC.view];
[self.secondVC didMoveToParentViewController:self];
}
}
#end
What you should do is to make a subview, instead of making a new UIViewController. In only very special cases would you ever put one UIViewController inside another. Basically every 'screen' should have one UIViewController, but you shouldn't put one inside another.

Delegate method in the first view does not get invoked from the second view

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?

Resources